Warning: this is not a question, but a recap of WPF Style working. The question is if this summary is right.
I read that in a style definition you can get rid of the TargetType if you include the control's class name in the Property name. That is this:
<Style x:Key="SomeKey" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red"/>
</Style>
becomes this:
<Style x:Key="SomeKey">
<Setter Property="Button.Foreground" Value="Red"/>
</Style>
Oh great, this means that, given three controls:
<StackPanel Height="40" Orientation="Horizontal">
<Button Style="{StaticResource MyStyle}" Content="First"/>
<TextBox Style="{StaticResource MyStyle}" Text="Second"/>
<Label Style="{StaticResource MyStyle}" Content="Third"/>
</StackPanel>
I can do something like this:
<Window.Resources>
<Style x:Key="MyStyle">
<Setter Property="Button.Foreground" Value="Red"/>
<Setter Property="TextBox.BorderBrush" Value="DarkBlue"/>
<Setter Property="Label.Background" Value="LightPink"/>
<Setter Property="Control.Margin" Value="4,0,0,0"/>
</Style>
</Window.Resources>
That is: first button should be standard but with red text; second should be standard but with DarkBlue Border. Third should be with LightPink foreground.
This is what I get instead:
That is: except for the third that is a label and its BorderThickness defaults to 0, every style goes to every control.
After a bit of digging it seems to me that all the mechanics of applying a style boils down to what follows. Since it seems to be quite rudimentary, I'm wondering if this description is right or if I'm missing something important.
Phase 1: defining a style
1.a A style gets a key explicitly if x:Key is set (<Style x:Key="MyStyle">
)
1.b If x:Key is not set, TargetType has to be set. (<Style TargetType="{x:Type Button}">
). Internally, it assigns the style a key that is the name of the type specified in TargetType
1.c If both TargetType is set and one or more Setter are defined with the syntax <Setter Property="Class.Property" Value=.../>
, there is no check of consistence between the TargetType and the Classes values in the Setters.
That is, this is legal:
<Style x:Key="MyStyle" TargetType="{x:Type Button}">
<Setter Property="Control.Margin" Value="4,0,0,0"/>
</Style>
even if it has little sense, while the following may be useful in (at least) one case.
<Style x:Key="MyStyle" TargetType="{x:Type Control}">
<Setter Property="TextBox.Text" Value="just an example"/>
</Style>
That is almost everything regarding style definition.
Pahse 2: associating the style with controls
2.a Does the control have a style defined (<Button Style="{StaticResource MyStyle}">
)? Lookup in the resources if there is such a style. If there is, check if it has also a TargetType; if the control is not that class of a subclass, raise the exception:
XamlParseException. Exception: Cannot find resource named 'MyStyle'. Resource names are case sensitive
So, in this case TargetType is not meant for filtering. It just has to match.
2.b If the control doesn't have a style defined, lookup the resources for a style with the key equals to the control's class name. This comes from a style defined with only TargetType. If found, go on to apply phase.
Notice that styles that are defined with a TargetType of a superclass of the control wont be applied. They have to match exactly. This is another 'limitation' of a style system that is far from the complexity of CSS; WPF styles seem to support little more than a dictionary lockups.
Phase 3: Applying the style
At this point, a control has a style to apply. If the style defined a TargetType, it matches with the control (the control is of that type or a subtype of the type defined in the style applied).
The style is a set of Setters that may or may not have their own specification of target control(with: <Setter Property="Control.Foreground" Value="Red"/>
; without: <Setter Property="Foreground" Value="Red"/>
).
It seems (and my previous example seems to proof it) that by design the class specification at the setter level is not meant for further refining or filtering. What is meant for? Good questions, I'll go back to it later on.
How does it work then? It simply ignores the class information (if present) and it goes on trying to apply every setter to the control. That is why even if I
defined a Setter like this:
<Setter Property="Label.Background" Value="LightPink"/>
all of the three controls get the LightPink background, not only the Label.
And that's the reason of this post. I couldn't find a complete explanation of how styles really work. All the information that I could find was limited to showcasing some basic usage; that is they don't show you how to approach a complex solution that requires a much more detailed knowledge.
Lastly, why should I ever specify classes names in Setters if the famework doesn't use them for filtering; it's just a useless repetition. Why that feature at all?
<Style x:Key="MyStyle">
<Setter Property="Control.Foreground" Value="Red"/>
<Setter Property="Control.BorderBrush" Value="DarkBlue"/>
<Setter Property="Control.Background" Value="LightPink"/>
<Setter Property="Control.Margin" Value="4,0,0,0"/>
</Style>
The only case that I could think of is this; i cant set a "Text" property without specifying TextBox, since Control doesn't have a Text property. Again, it doesn't mean filtering and I suppose that if another control, not a subclass of Text had a different Text property, it would get set also.
<Style x:Key="MyStyle" TargetType="{x:Type Control}">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="BorderBrush" Value="DarkBlue"/>
<Setter Property="Background" Value="LightPink"/>
<Setter Property="Margin" Value="4,0,0,0"/>
<Setter Property="TextBox.Text" Value="just a test"/>
</Style>