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 avoidDynamicResource
with the goal to improve the application's performance. StaticResource
does not allow forward references, whereasDynamicResource
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 usingDynamicReference
), then the XAML engine will optimize the reference by treating it as aStaticResource
, 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 aDynamicResource
). This resource can be targeted by aStoryboard
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}" />