在另一个 DynamicResource 中引用一个 StaticResource
Referencing a StaticResource in another DynamicResource
如果我更改一些用作 StaticResource 的资源,那么所有引用的控件都会受到影响。
如果资源被称为 DynamicResource,则不会。
但是在 DynamicResource 中称为 StaticResource 的一些资源怎么样?
<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
引用 TabItemBrush
使用 DynamicResource
.
TabItemBrush
使用 StaticResource
.
引用 GradientBrush
GradientBrush
使用 StaticResource
.
引用 Color
<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>
我认为当我更改 TabControl
中的选定项目时,所有 TabItem
都变成相同的颜色,因为除了 TabItemBrush
.[=26= 之外的所有资源都被称为 StaticResource ]
但只有选中的项目颜色是蓝色,其他都是红色。
此外,如果我将所有 StaticResource 更改为 DynamicResource,它将无法正常工作(全红或全蓝)。
为什么 StaticResource 就像不共享一样工作,而 DynamicResource 像共享一样工作?
我发现你的问题很难理解。但是,我认为您很困惑,因为您不了解 StaticResource
和 DynamicResource
之间的区别。
- 顾名思义,
StaticResource
引用 will/can 永远不会改变(它们是静态的)。
- 使用
StaticResource
引用的资源仅在 compile-time 解析一次。
- 顾名思义,
DynamicResource
引用可以更改(它们是动态的)。
- 使用
DynamicResource
引用的资源在运行时解析。
- 由于
StaticResource
引用在 compile-time 解析,XAML 解析器可以避免创建中间查找表达式(然后在运行时执行)的开销。
这就是为什么您应该始终避免 DynamicResource
以提高应用程序性能的原因。
StaticResource
不允许前向引用,而 DynamicResource
允许 - 但前向引用方面在您的上下文中并不重要。
"If I change some resource used as StaticResource then all the
controls which referring to is affected."
这绝对不正确。您不能更改引用为 StaticResource
的资源,然后观察到这些更改会更新引用对象 - 这不可能从未发生过(请参阅上面对基本特征的解释)。
您在这里的意思可能有所不同。
"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."
这是正确的行为。您已经使用 VisualStateManager
为“Selected”和“Unselected”定义了 VisualState
个对象。根据这些状态,单击 TabItem
会将 selected 项目的 Background
修改为蓝色,将所有其他未selected 项目修改为红色。
"Moreover if i change all the StaticResource to DynamicResource, it works >incorrectly ( all red or all blue)."
这是 XAML 引擎在动画上下文中的特殊行为:它将冻结 Storyboard
。
这意味着,所有参与的子实例,如 AnimationTimeline
(例如,ColorAnimation
)或一般的 Animatable
类型,都被冻结,因此 不可更改(他们都继承了Freezable
).
因此,所有引用的资源,如 Brush
必须是静态的,并且在 compile-time 处已知:如果引用实例需要冻结,则不能使用 DynamicResource
引用资源.
Storyboard
中使用的资源必须引用为 StaticResource
.
现在,假设一个元素(例如 a Border
)使用 DynamicResource
来引用本身包含对其他资源的引用的资源:
- 如果元素使用
DynamicResource
引用纯静态资源(本身不使用 DynamicReference
引用其他资源的资源),则 XAML 引擎将优化通过将其视为 StaticResource
来引用以避免开销,并将其存储在静态资源的内部查找 table 中(请记住,StaticResource
在性能成本方面比查找 DynamicResource
)。此资源可以作为 Storyboard
动画的目标,因为它现在是静态的:
<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}" />
- 如果元素引用的资源本身引用了至少一个使用
DynamicResource
的资源,那么引用将保持动态并且将防止 Storyboard 被冻结和动画无法工作等:
<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}" />
您遇到的另一个效果是,当您 select TabItem 时,所有项目都具有相同的背景。
这与 XAML 引擎处理资源的方式有关。使用 StaticResource 引用资源会导致资源默认共享。
您有两种解决此问题的方法:
- 通过将
x:Shared
属性设置为 false
: 将静态引用的每个参与资源声明为 non-shared
<ResourceDictionary>
<Color x:Key="Color"
x:Shared="False">#000000</Color>
<LinearGradientBrush x:Key="GradientBrush"
x:Shared="False"
EndPoint="0,0"
StartPoint="0,1" >
<GradientStop Color="{StaticResource Color}" Offset="0" />
<GradientStop Color="{StaticResource Color}" Offset="1" />
</LinearGradientBrush>
</ResourceDictionary>
<Border Background="{StaticResource GradientBrush}" />
- 或者,将动画资源定义为内联。这样每个
TabItem
边框都会有其 own/non-shared Brush
资源:
<ResourceDictionary>
<Color x:Key="Color">#000000</Color>
</ResourceDictionary>
<Border>
<Border.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="0,1" >
<GradientStop Color="{StaticResource Color}" Offset="0" />
<GradientStop Color="{StaticResource Color}" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
如果我更改一些用作 StaticResource 的资源,那么所有引用的控件都会受到影响。
如果资源被称为 DynamicResource,则不会。
但是在 DynamicResource 中称为 StaticResource 的一些资源怎么样?
<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
引用 TabItemBrush
使用 DynamicResource
.
TabItemBrush
使用 StaticResource
.
GradientBrush
GradientBrush
使用 StaticResource
.
Color
<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>
我认为当我更改 TabControl
中的选定项目时,所有 TabItem
都变成相同的颜色,因为除了 TabItemBrush
.[=26= 之外的所有资源都被称为 StaticResource ]
但只有选中的项目颜色是蓝色,其他都是红色。
此外,如果我将所有 StaticResource 更改为 DynamicResource,它将无法正常工作(全红或全蓝)。
为什么 StaticResource 就像不共享一样工作,而 DynamicResource 像共享一样工作?
我发现你的问题很难理解。但是,我认为您很困惑,因为您不了解 StaticResource
和 DynamicResource
之间的区别。
- 顾名思义,
StaticResource
引用 will/can 永远不会改变(它们是静态的)。 - 使用
StaticResource
引用的资源仅在 compile-time 解析一次。 - 顾名思义,
DynamicResource
引用可以更改(它们是动态的)。 - 使用
DynamicResource
引用的资源在运行时解析。 - 由于
StaticResource
引用在 compile-time 解析,XAML 解析器可以避免创建中间查找表达式(然后在运行时执行)的开销。
这就是为什么您应该始终避免DynamicResource
以提高应用程序性能的原因。 StaticResource
不允许前向引用,而DynamicResource
允许 - 但前向引用方面在您的上下文中并不重要。
"If I change some resource used as StaticResource then all the controls which referring to is affected."
这绝对不正确。您不能更改引用为 StaticResource
的资源,然后观察到这些更改会更新引用对象 - 这不可能从未发生过(请参阅上面对基本特征的解释)。
您在这里的意思可能有所不同。
"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."
这是正确的行为。您已经使用 VisualStateManager
为“Selected”和“Unselected”定义了 VisualState
个对象。根据这些状态,单击 TabItem
会将 selected 项目的 Background
修改为蓝色,将所有其他未selected 项目修改为红色。
"Moreover if i change all the StaticResource to DynamicResource, it works >incorrectly ( all red or all blue)."
这是 XAML 引擎在动画上下文中的特殊行为:它将冻结 Storyboard
。
这意味着,所有参与的子实例,如 AnimationTimeline
(例如,ColorAnimation
)或一般的 Animatable
类型,都被冻结,因此 不可更改(他们都继承了Freezable
).
因此,所有引用的资源,如 Brush
必须是静态的,并且在 compile-time 处已知:如果引用实例需要冻结,则不能使用 DynamicResource
引用资源.
Storyboard
中使用的资源必须引用为 StaticResource
.
现在,假设一个元素(例如 a Border
)使用 DynamicResource
来引用本身包含对其他资源的引用的资源:
- 如果元素使用
DynamicResource
引用纯静态资源(本身不使用DynamicReference
引用其他资源的资源),则 XAML 引擎将优化通过将其视为StaticResource
来引用以避免开销,并将其存储在静态资源的内部查找 table 中(请记住,StaticResource
在性能成本方面比查找DynamicResource
)。此资源可以作为Storyboard
动画的目标,因为它现在是静态的:
<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}" />
- 如果元素引用的资源本身引用了至少一个使用
DynamicResource
的资源,那么引用将保持动态并且将防止 Storyboard 被冻结和动画无法工作等:
<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}" />
您遇到的另一个效果是,当您 select TabItem 时,所有项目都具有相同的背景。
这与 XAML 引擎处理资源的方式有关。使用 StaticResource 引用资源会导致资源默认共享。
您有两种解决此问题的方法:
- 通过将
x:Shared
属性设置为false
: 将静态引用的每个参与资源声明为 non-shared
<ResourceDictionary>
<Color x:Key="Color"
x:Shared="False">#000000</Color>
<LinearGradientBrush x:Key="GradientBrush"
x:Shared="False"
EndPoint="0,0"
StartPoint="0,1" >
<GradientStop Color="{StaticResource Color}" Offset="0" />
<GradientStop Color="{StaticResource Color}" Offset="1" />
</LinearGradientBrush>
</ResourceDictionary>
<Border Background="{StaticResource GradientBrush}" />
- 或者,将动画资源定义为内联。这样每个
TabItem
边框都会有其 own/non-sharedBrush
资源:
<ResourceDictionary>
<Color x:Key="Color">#000000</Color>
</ResourceDictionary>
<Border>
<Border.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="0,1" >
<GradientStop Color="{StaticResource Color}" Offset="0" />
<GradientStop Color="{StaticResource Color}" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>