WPF & XAML: Multiple Style Inheritance and Markup Extensions

WPF provides a way for a Style to inherit from  another Style, using the BasedOn attribute.   This is basically single inheritance for styles.

We recently came across a “need” to inherit from multiple styles.  Our UX designers had globally restyled the look of some of our controls, and our developers had used styles and triggers for enabling & disabling (amoung other things) some local controls.

We could have created a brand new Style — basing it on the UX Style (for example) and then cutting and pasting the style elements from the second style.  However, we weren’t too keen on duplicating the second Style’s trigger logic. 

Since WPF/XAML doesn’t include a built-in way to inherit from multiple styles (as it does for inheriting from a single style), we decided to create our own way of doing just that, using a custom Markup Extension.

The MergedStylesExtension merges two styles together, and returns a new Style.  It does this by utilizing the BasedOn attribute to inherit from the first Style, and then it programmatically copies all of the setter and trigger elements from the second Style.

A basic version of it is as follows:

[MarkupExtensionReturnType(typeof(Style))]
public class MergedStylesExtension : MarkupExtension
{
   public Style BasedOn    { get; set; }
   public Style MergeStyle { get; set; }
 
   public override object ProvideValue(IServiceProvider
                                       serviceProvider)
   {
      if (null == MergeStyle)
         return BasedOn;
 
      Style newStyle = new Style(BasedOn.TargetType,
                                 BasedOn);
 
      MergeWithStyle(newStyle, MergeStyle);
 
      return newStyle;
   }   

   private static void MergeWithStyle(Style style,
                                      Style mergeStyle)
   {
      // Recursively merge with any Styles this Style
      // might be BasedOn.
      if (mergeStyle.BasedOn != null)
      {
          MergeWithStyle(style, mergeStyle.BasedOn);
      }

      // Merge the Setters...
      foreach (var setter in mergeStyle.Setters)
         style.Setters.Add(setter);
    
      // Merge the Triggers...
      foreach (var trigger in mergeStyle.Triggers)
         style.Triggers.Add(trigger);
    }
}

 

Using the custom extension method in XAML should be similar to using other, built-in extensions:

  

<Button
   Style="{ext:MergedStyles
            BasedOn={StaticResource FirstStyle}
            MergeStyle={StaticResource SecondStyle}}"
   Content="This is an example of a merged style" />

 

However, due to a WPF bug (see: http://www.hardcodet.net/2008/04/nested-markup-extension-bug), this won’t quite work.  Instead, we need to resort to property element syntax:

 
<Button 

   Content="This is an example of a merged style">
   <Button.Style>
      <ext:MergedStyles
          BasedOn="{StaticResource FirstStyle}"
          MergeStyle="{StaticResource SecondStyle}"/>
   </Button.Style>
</Button>

 

You can also define the merged style in the Resources section of your XAML file, if you intend to use it in more than one place:

<Style x:Key="MergedStyle"
       TargetType="{x:Type Control}">
    <Style.BasedOn>
       <ext:MergedStyles
           BasedOn="{StaticResource FirstStyle}"
           MergeStyle="{StaticResource SecondStyle}"/>
    </Style.BasedOn>
</Style>

For more information on creating your own custom Markup Extensions, see: http://dotnet.dzone.com/news/extend-wpf-add-your-own-keywor.

20 Responses to WPF & XAML: Multiple Style Inheritance and Markup Extensions

  1. Ryan says:

    Question, this helped me with an issue I’m trying solve, but only to a point. I need to support the following:

    I have three base styles that may be swapped out by a choice the user makes; let’s call them Style FontSizeSmall, Style FontSizeDefault, and Style FontSizeLarger.

    From there, I have a TextStyleBase style that I want to be my base style for all TextBlocks, TextBoxes, etc. (but allow another level of inheritence). It uses a class that inherits from MarkupExtension. All this class does is read from an Application property that tells which of the above styles to use. The resulting style markup looks like:

    All of the the above is in the App.xaml.

    In the window utilizing the style, I have this in the resources:

    Then that style is applied to a TextBlock:

    It works. Once. If I change the setting that the BaseStyleExtension class reads from, it doesn’t matter since it never gets called again.

    I understand that what is happening is that once the style is applied, it never takes a second look at the style.

    How can I make it? Any ideas?

  2. Ryan says:

    Crud – none of the code I pasted showed up.

  3. […] Others have written great solutions to merge two styles using markup extensions. However, I wanted a solution that provided the ability to merge an unlimited number of styles, which is a little bit trickier. […]

  4. custom software development company says:

    Nivista is Custom Software Development Company offers services in .NET Application

    Development, Dynamic CRM, Sharepoint Application Developement, Business Intelligence

    Reporting, OffShore Software Development etc. We are expertise in providing IT and ITES

    solutions. Custom Software Development Company

  5. […] Others have written great solutions to merge two styles using markup extensions. However, I wanted a solution that provided the ability to merge an unlimited number of styles, which is a little bit trickier. […]

  6. train cases says:

    makeup case…

    […]WPF & XAML: Multiple Style Inheritance and Markup Extensions « A Software Developer’s Weblog[…]…

  7. extensions sheffield…

    […]WPF & XAML: Multiple Style Inheritance and Markup Extensions « A Software Developer’s Weblog[…]…

  8. call center solutions software…

    […]WPF & XAML: Multiple Style Inheritance and Markup Extensions « A Software Developer’s Weblog[…]…

  9. Lighting says:

    Lighting…

    […]WPF & XAML: Multiple Style Inheritance and Markup Extensions « A Software Developer’s Weblog[…]…

  10. Deselt says:

    This is a great tip particularly to those new to the blogosphere.
    Simple but very precise info… Thank you for sharing this one.
    A must read post!

  11. You really produced a handful of outstanding stuff in ur blog post, “WPF
    & XAML: Multiple Style Inheritance and Markup Extensions
    A Software Developers Weblog”. I am going to remain
    coming back again to ur website in the near future. Thx -Allison

  12. I used to be suggested this website by way of my cousin.
    I am no longer positive whether or not this post is written through him as nobody else realize
    such distinctive about my difficulty. You are amazing! Thank
    you!

  13. Attractive section of content. I simply stumbled upon your website and in accession capital to say that I get in fact enjoyed account your weblog posts.
    Any way I’ll be subscribing for your augment or even I fulfillment
    you get right of entry to persistently fast.

  14. I delight in, lead to I discovered just what I was looking for.

    You’ve ended my four day long hunt! God Bless you man. Have a great day. Bye

  15. […] But if styles are very complex or have lot of styles then it will be painful. Fortunately I found this article which describes how we can achieve multiple style inheritance using Markup Extension. […]

  16. […] WPF & XAML: Multiple Style Inheritance and Markup … – 3/1/2009 · WPF provides a way for a Style to inherit from another Style, using the BasedOn attribute. This is basically single inheritance for styles…. […]

  17. […] 다른 사람들 은 태그 확장을 사용하여 두 가지 스타일을 병합하는 훌륭한 솔루션을 작성했습니다. 그러나 무제한 스타일을 병합하는 기능을 제공하는 솔루션을 원했습니다. […]

  18. […] 다른 사람들 은 태그 확장을 사용하여 두 가지 스타일을 병합하는 훌륭한 솔루션을 작성했습니다. 그러나 무제한 스타일을 병합하는 기능을 제공하는 솔루션을 원했습니다. […]

  19. become a Life coach – 3 compelling reasons why you should consider a career in this field

    WPF & XAML: Multiple Style Inheritance and Markup Extensions | A Software Developer’s Weblog

  20. fun88 says:

    fun88

    WPF & XAML: Multiple Style Inheritance and Markup Extensions | A Software Developer’s Weblog

Leave a reply to Ryan Cancel reply