Home > Back-end >  Referencing a StaticResource in another DynamicResource
Referencing a StaticResource in another DynamicResource

Time:03-30

If I change some resource used as StaticResource then all the controls which referring to is affected.

And it does not in case the resource is referred as DynamicResource.

But how about some resource referred as StaticResource in a DynamicResource?

        <Color x:Key="Color">#000000</Color>
        
        <LinearGradientBrush  x:Key="GradientBrush" EndPoint="0,0" StartPoint="0,1" >
            <GradientStop Color="{StaticResource Color}"  Offset="0" />
            <GradientStop Color="{StaticResource Color}"  Offset="1" />
        </LinearGradientBrush>

        <DrawingBrush x:Key="TabItemBrush" >
            <DrawingBrush.Drawing>
                <GeometryDrawing Brush="{StaticResource GradientBrush}">
                    <GeometryDrawing.Geometry>
                        <RectangleGeometry Rect="0 100 100 100"/>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>
      <Style TargetType="{x:Type TabItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid x:Name="Root">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="SelectionStates">
                                    <VisualState x:Name="Unselected" >
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).(DrawingBrush.Drawing).(GeometryDrawing.Brush).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
                                                <EasingColorKeyFrame KeyTime="0" Value="Red" />
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Selected">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).(DrawingBrush.Drawing).(GeometryDrawing.Brush).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
                                                <EasingColorKeyFrame KeyTime="0" Value="Blue" />
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="Border" Background="{DynamicResource TabItemBrush}">
                                <ContentPresenter x:Name="ContentSite"  VerticalAlignment="Center" 
                                                  HorizontalAlignment="Center" ContentSource="Header"  
                                                  Margin="12,2,12,2"  RecognizesAccessKey="True" />
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Border in TabItem refers TabItemBrush using DynamicResource.

TabItemBrush refers GradientBrush using StaticResource.

GradientBrush refers Color using StaticResource.

    <StackPanel>
        <TabControl>
            <TabItem Header="AAA" >AAA</TabItem>
            <TabItem Header="BBB" >BBB</TabItem>
            <TabItem Header="CCC" >BBB</TabItem>
        </TabControl>
        <Border Background="{DynamicResource GradientBrush}" Height="1000" Width="1000"/>
    </StackPanel>

I thought that all of TabItem change to same color when I change a selected item in TabControl because all of resources is referred as StaticResource except TabItemBrush.

But only the color of selected item is blue and the others red.

Moreover if i change all the StaticResource to DynamicResource, it works incorrectly ( all red or all blue).

Why StaticResource works as if it is not shared and DynamicResource as shared?

CodePudding user response:

I found your question very difficult to understand. However, I think you are confused because you are not understanding the difference between StaticResource and DynamicResource.

  • As the names suggest, StaticResource references will/can never change (they are static).
  • Resources referenced using StaticResource are resolved only once at compile-time.
  • As the names suggest, DynamicResource references can change (they are dynamic).
  • Resources referenced using DynamicResource are resolved on runtime.
  • Since StaticResource references are resolved at compile-time, the XAML parser can avoid the overhead of creating an intermediate lookup expression (which is then executed at runtime).
    This is why you should always avoid DynamicResource with the goal to improve the application's performance.
  • StaticResource does not allow forward references, whereas DynamicResource does - but the forward reference aspect doesn't matter in your context.

"If I change some resource used as StaticResource then all the controls which referring to is affected."

This is definitely not correct. You can't change resources referenced as StaticResource and then observe that those changes update the referencing objects - this can't have never happened (see explanation of the fundamental characteristics above).
You probably meant something different here.

"I thought that all of TabItem change to same color when I change a selected >item in TabControl because all of resources is referred as StaticResource >except TabItemBrush.

But only the color of selected item is blue and the others red."

This is the correct behavior. You have defined the VisualState objects for "Selected" and "Unselected" with the VisualStateManager. According to these states clicking a TabItem will modify the Background of the selected item to blue and all other unselected items to red.

"Moreover if i change all the StaticResource to DynamicResource, it works >incorrectly ( all red or all blue)."

Here comes in the special behavior of the XAML engine in context of animations: it will freeze the Storyboard.
This means, all participating child instances like AnimationTimeline (e.g., ColorAnimation), or Animatable types in general, are frozen and therefore not changeable (they all inherit Freezable).

As a consequence, all referenced resources like Brush must be static and known at compile-time: you can't reference resources using DynamicResource if the referencing instance needs to be frozen.
Resources used in a Storyboard must be referenced as StaticResource.

Now, given the case that an element, for example a Border, uses DynamicResource to reference a resource that itself contains references to other resources:

  • If the element uses DynamicResource to reference a pure static resource (a resource that doesn't itself references other resources using DynamicReference), then the XAML engine will optimize the reference by treating it as a StaticResource, to avoid the overhead, and store it in the internal lookup table for the static resources (remember, StaticResource is much cheaper in terms of performance costs than looking up a DynamicResource). This resource can be targeted by a Storyboard animation as it is now static:
<ResourceDictionary>
  <Color x:Key="Color">#000000</Color>
        
  <!-- Resource is treated as a static resource -->
  <LinearGradientBrush  x:Key="GradientBrush" EndPoint="0,0" StartPoint="0,1" >
    <GradientStop Color="{StaticResource Color}"  Offset="0" />
    <GradientStop Color="{StaticResource Color}"  Offset="1" />
  </LinearGradientBrush>
</ResourceDictionary>

<!-- The lookup behavior is optimized to StaticResource.
     A Storyboard therefore will be able to animate the Background resource. 
-->
<Border Background="{DynamicResource GradientBrush}" />
  • If the resource that an element references is itself referencing at least one resource using DynamicResource, then the reference will remain dynamic and will prevent e.g., the Storyboard from being frozen and the animation won't work:
<ResourceDictionary>
  <Color x:Key="Color">#000000</Color>
        
  <!-- Resource is treated as a dynamic resource, 
       because it contains at least one DynamicResource reference. 
  -->
  <LinearGradientBrush  x:Key="GradientBrush" EndPoint="0,0" StartPoint="0,1" >
    <GradientStop Color="{DynamicResource Color}"  Offset="0" />
    <GradientStop Color="{StaticResource Color}"  Offset="1" />
  </LinearGradientBrush>
</ResourceDictionary>

<!-- The lookup behavior is now DynamicResource and not optimized. 
     A Storyboard won't be able to animate the properties of the resource as it can't be frozen. 
 -->
<Border Background="{DynamicResource GradientBrush}" />
  •  Tags:  
  • wpf
  • Related