2
votes

I'm working on an already existing project where I can't make the styling work the way I want.

I start from an application where:

  • there is a WhistlerBlue.xaml file in a Resources folder.
  • the styles inside the file use TargetType to automatically apply them
  • there is a style defined for the Expander control (more on this, next)
  • I don't want to mess with this file.
  • the file is explicitly used in the application via merged resources in the App.xaml

Up to this point, everything works fine.


Then...

I'm building a custom control which is derived from Expander:

internal partial class TestExpander : Expander

By creating the custom control a Theme folder has been added to the project by VStudio, with the usual Generic.xaml file inside. In this file I've created the style for my custom control:

<Style TargetType="{x:Type local:TestExpander}" BasedOn="{StaticResource {x:Type Expander}}">
    <Style.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibility"/>
    </Style.Resources>

    <Setter Property="ExpandDirection" Value="Down"/>
    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
    <Setter Property="HorizontalAlignment" Value="Stretch"/>
    <Setter Property="VerticalAlignment" Value="Top"/>
    <Setter Property="Cursor" Value="Hand"/>
</Style>

Obviously in the code of the custom control I have:

static TestExpander()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TestExpander), new FrameworkPropertyMetadata(typeof(TestExpander)));
        }

What I expect is for my TestExpander to inherit the Expander style defined in WhistlerBlue.xaml, add it's own customizations via its own style, and they all lived happily ever after.

It's not happening. Where am I wrong?

1
Do you have the Resource Dictionary that contains the style template you're trying to inherit from declared as a ResourceDictionary.MergedDictionaries in your new Resource Dictionary (generic.xaml) so it can find it?Chris W.
@ChrisW. you are my hero.motoDrizzt
Hah no worries, we've all been there. Cheers. :)Chris W.
@ChrisW. Yeah, but I'm developing WPF apps since the first day the tech have been available...I shouldn't do those mistakes :-\ Anyway...what about posting an answer, so I can accept it? xDmotoDrizzt
Sure, and if it makes you feel any better, I just spent well more than an hour trying to figure out something while doing some massaging of data in multiple complex object arrays to find what a fresh pair of eyes probably would have found in seconds and called a rookie mistake lol. It's good to stay humble in our business. :)Chris W.

1 Answers

3
votes

So when we're creating our architecture of inheritance for various things it's easy to forget the order of how things receive their inherited parts. So when we for example place a BasedOn that's looking directly at x:Type then it's just going to go look for it in the order of inheritance it has available right?

By that when it's looking for x:Type and it's not aware of an override in another dictionary...he just goes straight to the default original. However if we inject that dictionary that includes what you're wanting to inherit from via ResourceDictionary.MergedDictionaries then it knows to go look at him first before he gets back to the framework defaults and all is good in the world.

On a side note though, when you merge dictionaries for inheritance in such a way you have to be attentive to how you're doing it or you can cause a performance hit. Since by saying it's a merged dictionary....at runtime it will take everything in the dictionary being merged and make a copy of all of it over into the new one.

So for this instance....if it were me, I would probably just omit that generic.xaml dictionary content if it's not really necessary and place that template in the existing dictionary just under where the template it's looking to inherit from is placed. Then you're not making another copy of an entire dictionary, it will still get its inheritance, and life should be peachy. Hope this helps. :)