Scoping rules in WPF

Staticresources are resolved at parsing time

A staticresource is read when the xaml is read. This is demonstrated in the following example

<Style TargetType="{x:Type TextBlock}">
 <Setter Property="Foreground" Value="{StaticResource NormalTextColor}"/>
 </Style>

<SolidColorBrush x:Key="NormalTextColor" Color="Yellow"></SolidColorBrush>

At the moment the style is created, NormalTextColor is not defined yet. And so it stays whenever later that style is applied. If we swap the NormalTextColor definition and the Style then it will be a fixed yellow.

Dynamicresources are resolved whenever necessary

If we modify the StaticResource in a DynamicResource, then that example will behave correctly, and every textblock will have a yellow foreground.

Resource Lookup

The resource lookup goes from child to parent.

<Window x:Class="WinWpfTests.MainWindow"
 Title="MainWindow" Height="450" Width="800">
 <Window.Resources>
   <SolidColorBrush x:Key="NormalTextColor" Color="Orange"></SolidColorBrush>
 </Window.Resources>
 <StackPanel Grid.Row="1" Orientation="Horizontal">
   <StackPanel.Resources>
     <SolidColorBrush x:Key="NormalTextColor" Color="Red"></SolidColorBrush> 
   </StackPanel.Resources>
 <TextBlock Text="Some text"/>
 </StackPanel>
</Window>

This means that any textblock within the stackpanel will be colored red, while the textblocks outside the stackpanel yet inside the window will be orange. And ifg the application.xaml is defined as in our first example, then any other window will be yellow.

It might be necessary to restyle multiple controls

Whenever a textblock is used it will have the provided style. A label however has its own foreground color defined, and so requires an extra style.

<Style TargetType="{x:Type TextBlock}">
 <Setter Property="Foreground" Value="{DynamicResource NormalTextColor}"/>
 </Style>
<Style TargetType="{x:Type Label}">
 <Setter Property="Foreground" Value="{DynamicResource NormalTextColor}"/>
 </Style>

Resource lookup through templates

ControlTemplates provide a way to render a particular element differently.  The  dynamic lookup still goes from the lexical point of insertion up the logical tree. Thus the following fragment

 <Style x:Key="ModifiedLabel" TargetType="{x:Type Label}">
 <Setter Property="Template">
 <Setter.Value>
 <ControlTemplate TargetType="{x:Type Label}">
 <StackPanel Orientation="Vertical">
 <TextBlock Text="Zhe legend"/>
 <ContentPresenter/>
 </StackPanel>
 </ControlTemplate>
 </Setter.Value>
 </Setter>
 </Style>

Will render both the ‘Zhe legend’ as well as the actual content of the label using the same dynamicresource: that is they will both have the same color, even if the controltemplate was defined in a different file. (One could expect that ‘Zhe Legend’ would follow a lookup hierarchy going from the definition of the template, while the ContentPresenter would follow a different hierarchy)

The logical parent with controltempaltes

The logical parent of the contentpresenter is the controltemplate, which is the same as the control being templated. Thus if we set the template of a label to something, and then define a resources in the controltemplate (as ControlTempalte.Resources), then these resources are part of the label, and thus are visibly to dynamicresources applied to the contentpresenter.

Yet, if we place the resources to a subelement within the controltemplate, then they are not part of the label, and thus not part of the logical chain of parents from the contentpresenter.

Under the assumption that the default color has been set to red in the App.xaml, we have two ways to define a controltemplate, with two different results

 

Who has priority ?

 

Because both the ControlTemplate and the original instantiation both access the same resource dictionary frame, it is useful to figure out who has priority. The answer is: the controltempalte its resources are applied first, afterwards those defined in the actual instantiation of the control.

Leave a Reply

Your email address will not be published. Required fields are marked *