Styles in WPF.
Note on article’s inspiration: Article is based almost entirely on Windows Presentation Foundation Unleashed book which I recommend for all WPF learners.
Content:
1. What is style. Why do I need it?
2. Basic styling scenario.
3. How are elements connected with styles? – Named and typed styles.
4. I have typed style for Control type but it doesn’t work. Not a single subclass of Control has been changed. If I change it to named style everything is ok. What’s wrong? – Differences between named and typed style in target element’s type matching.
1. What is style. Why do I need it?
Style is not something you couldn’t live without. It’s yet another mechanism provided to make your life easier. If in your window you have several buttons and you want them all to have their text displayed in red we could set in each one it’s Foreground property’s value to red. However, since we all know the value of gathering such commonalities in one place we will use styles as a very handy tool in such cases. It’s more less like CSS. If you know CSS you get the idea.
2. Basic styling scenario.
We have a window layout containing several buttons.
1: <Window2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">4: <StackPanel Orientation="Vertical">5: <Button Content="First" />6: <Button Content="Second" />7: </StackPanel>8: </Window>
We want all buttons to have their text displayed in red so we define style that will do that for us.
1: <Window2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">4:5: <Window.Resources>6: <Style TargetType="{x:Type Button}">7: <Setter Property="Foreground" Value="Red" />8: </Style>9: </Window.Resources>10:11: ...12:13: </Window>
And here it is, our first style changing Foreground of all Buttons to red. Generally that’s it. You can add more setters to our style to customize more properties of all Button elements.
3. How are elements connected with styles? – Named and typed styles.
This one is important and at first a bit tricky. There are several ways to tell Button’s element instance that it should use our style.
- define so called named style and assign it to each Button’s instance explicitly
First button has it’s style set. Second one will stay unchanged by our style.
1: <Window.Resources>
2: <Style x:Key="buttonStyle">3: <Setter Property="Foreground" Value="Red" />
4: </Style>
5: </Window.Resources>
6:
7: <StackPanel Orientation="Vertical">8: <Button Content="First" Style="{StaticResource buttonStyle}"/>
9: <Button Content="Second" />10: </StackPanel>
11:
- define typed style for specific type
In this case all elements of type Button in window’s scope will have our style set implicitly.
You might wonder why our style defined in resources dictionary does not have it’s x:Key set. Well actually it has. It is set implicitly to the value of TargetType attribute.1: <Window.Resources>
2: <Style TargetType="{x:Type Button}">3: <Setter Property="Foreground" Value="Red" />
4: </Style>
5: </Window.Resources>
6:
7: <StackPanel Orientation="Vertical">8: <Button Content="First"/>9: <Button Content="Second" />10: </StackPanel>
11:
You can choose the one that suits your needs best. Both have their advantages.
4. I have typed style for Control type but it doesn’t work. Not a single subclass of Control has been changed. If I change it to named style everything is ok. What’s wrong? – Differences between named and typed style in target element’s type matching.
There is one very important, because hard to be figured out, difference between named and typed style. It is about what type they do match and what they don’t.
Let’s look at named style example:
1: <Window.Resources>2: <Style x:Key="controlTemplate">3: <Setter Property="Control.Foreground" Value="Red" />4: </Style>5: </Window.Resources>6:7: <StackPanel Orientation="Vertical">8: <Button Content="First" Style="{StaticResource controlTemplate}"/>9: <Label Content="Second" Style="{StaticResource controlTemplate}"/>10: </StackPanel>
In this style we set a Foreground property of Control element. It means that we can set this style to any element that is a subclass of Control and it will still work. This is a very convenient mechanism and it seems to be so natural that when we define typed style like the following we might wonder what’s wrong.
1: <Window.Resources>2: <Style TargetType="{x:Type Control}">3: <Setter Property="Control.Foreground" Value="Red" />4: </Style>5: </Window.Resources>6:7: <StackPanel Orientation="Vertical">8: <Button Content="First" />9: <Label Content="Second" />10: </StackPanel>11:
It seems to have the same meaning as previous named style but there is a fundamental difference in type matching. Typed style matches only elements of exactly the same types. In our case it would be a Control type. WPF Unleashed explains that it was done to avoid surprises. For example, they say, you can create style for ToggleButton but you don’t want it to be applied to CheckBoxes which is an subclass of a ToggleButton. For named style there is no such problem because you apply style explicitly.