优化性能:应用程序资源
WPF 允许您共享应用程序资源,以便您可以在类型相似的元素之间保持一致的外观或行为。 本主题针对该领域提供了一些建议,以帮助您改进您的应用程序的性能。
有关资源的更多信息,请参见资源概述。
共享资源
如果您的应用程序使用自定义控件,并在 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>