WPF 允许共享应用程序资源,以便跨类似类型元素支持一致的外观或行为。 本主题在此领域提供了一些建议,可帮助你提高应用程序的性能。
有关资源的详细信息,请参阅 XAML 资源。
共享资源
如果应用程序使用自定义控件并在ResourceDictionary(或 XAML 资源节点)中定义资源,则建议您在Application或Window对象级别定义这些资源,或者在自定义控件的默认主题中定义它们。 在自定义控件 ResourceDictionary 中定义资源会对该控件的每个实例施加性能影响。 例如,如果在自定义控件的资源定义中包含性能密集型的画笔操作,并且存在多个自定义控件实例,则应用程序的工作集会显著增加。
若要说明这一点,请考虑以下事项。 假设你正在开发使用 WPF 的卡片游戏。 对于大多数纸牌游戏,你需要 52 张不同面孔的 52 张纸牌。 你决定实现卡片自定义控件,并在卡片自定义控件的资源中定义 52 个画笔(每个画笔代表卡片人脸)。 在主应用程序中,你最初创建此卡自定义控件的 52 个实例。 卡片自定义控件的每个实例都会生成 52 个对象实例 Brush ,从而在应用程序中总共提供 52 * 52 Brush 个对象。 通过将画笔从卡片自定义控件资源中移到 Application 或 Window 对象级别,或者在自定义控件的默认主题中定义画笔,可以减少应用程序的工作集,因为现在你正在卡控件的 52 个实例之间共享 52 支画笔。
如何在不复制的情况下共享画笔
如果有多个元素使用同一 Brush 对象,请将画笔定义为资源并引用它,而不是在 XAML 中内联定义画笔。 此方法将创建一个实例并重复使用它,而在 XAML 中定义画笔会为每个元素创建一个新实例。
以下标记示例说明了这一点:
<StackPanel.Resources>
<LinearGradientBrush x:Key="myBrush" StartPoint="0,0.5" EndPoint="1,0.5" Opacity="0.5">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="GoldenRod" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</StackPanel.Resources>
<!-- Non-shared Brush object. -->
<Label>
Label 1
<Label.Background>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5" Opacity="0.5">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="GoldenRod" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Label.Background>
</Label>
<!-- Shared Brush object. -->
<Label Background="{StaticResource myBrush}">Label 2</Label>
<Label Background="{StaticResource myBrush}">Label 3</Label>
尽可能使用静态资源
静态资源通过查找对已定义资源的引用,为任何 XAML 属性属性提供值。 该资源的查找行为类似于编译时查找。
另一方面,动态资源将在初始编译期间创建一个临时表达式,从而延迟查找资源,直到实际需要请求的资源值才能构造对象。 该资源的查找行为类似于运行时查找,这会对性能造成影响。 在应用程序中尽可能使用静态资源,仅在必要时使用动态资源。
以下标记示例演示了两种类型的资源的用法:
<StackPanel.Resources>
<SolidColorBrush x:Key="myBrush" Color="Teal"/>
</StackPanel.Resources>
<!-- StaticResource reference -->
<Label Foreground="{StaticResource myBrush}">Label 1</Label>
<!-- DynamicResource reference -->
<Label Foreground="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">Label 2</Label>