The Overriding Theme Of It All.

My Style Is Not Being Applied To My Elements!

I was playing around with a third party tool set and applied their theme to my app. This worked great and I was pretty happy with the overall look. As I progressed through my QA I noticed at least one weird byproduct of using themes.

I Said Collapse! (Please?)

The GUI element I call “Super Tiles” allows the user to select/deselect elements that are displayed in a ListBox. I do this by setting the DataTemplate to bind to an IsVisible property on the VM.

        
<DataTemplate x:Key="TotalISPerfWithExpectedCost">
    <UniformGrid Columns="2" HorizontalAlignment="Stretch" Visibility="{Binding IsVisible,
                    Converter={StaticResource boolToVisibility }}" >
    <Label Content="{Binding Label}" HorizontalContentAlignment="Right" />
    <Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox},
                         Mode=FindAncestor}, Path=DataContext.TotalISPerfWithExpectedCost}"
                         ContentStringFormat="{Binding ValueFormatString}" Grid.Column="1"
                         HorizontalContentAlignment="Right" />
        <i:Interaction.Behaviors>
            <behaviors:FrameworkElementDragBehavior/>
        </i:Interaction.Behaviors>
    </UniformGrid>
</DataTemplate>

 

ThemedNothingHidden

I can see that the vertical spacing between items is already wrong!

After applying the themes, I noticed that the vertical spacing between the “hidden” ListBoxItems was not being fully collapsed. Ugh!

Themed2ThingsHidden

See the weird space between the 4th and 5th Item?

 Even though I explicitly set the ListBox.ItemContainer.Style to have 0 margin etc , etc, the weird behavior persisted. To debug the issue I set the highlighting on the selected item to an extreme (and ugly Olive Drab) color. Sure enough, when running the app and selecting an item, the highlight would not render as expected. This was a hint that my explicitly set style was being overridden.

So that’s how it works.

Obviously this had to have something to do with the recently applied theme. Previously everything was working as expected, but now I seemed to have no control over the styles.

Here is the issue. When you set a theme, all the effected controls get their BasedOn properties set to the current theme’s resource dictionary. So what this means is that your explicitly set styles using TargetType etc. won’t do anything because you are not instructing WPF to override/change the theme’s  settings.

If the current theme is unchanged, the default BasedOn is also unchanged.

Solution

In order to inform WPF that I wanted to circumvent the theme’s definitions I needed to explicitly define a Style BasedOn the Static Definition of the ListboxItem.

First – Set up a Style in the Resources of your control and ref the Static x:Type of the desired element.

<Style x:Key="DataPointListItemStyle" TargetType="ListBoxItem" 
          BasedOn="{StaticResource {x:Type ListBoxItem}}">
   <Style.Resources>
     <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
                         Color="LightBlue"  Opacity=".5"/>
   </Style.Resources>
</Style>

Second – implement the Style in your element

<ListBox.ItemContainerStyle>
   <Style TargetType="ListBoxItem" BasedOn="{StaticResource DataPointListItemStyle}" />
</ListBox.ItemContainerStyle>

Check it out!

StyledNothingHidden

Smaller spacing vertically between items

Styled2ThingsHidden

“Hidden” elements are now fully collapsed! (avoiding the themed ListBoxItem definitions)

Cool! 🙂