优化性能:应用程序资源
WPF 允许共享应用程序资源,以便跨类似类型元素支持一致的外观或行为。 本主题在此领域提供了一些建议,可帮助你提高应用程序的性能。
有关资源的详细信息,请参阅 XAML 资源。
共享资源
如果应用程序使用自定义控件并在 ResourceDictionary(或 XAML 资源节点)中定义资源,建议在 Application 或 Window 对象级别定义资源,或在自定义控件的默认主题中定义资源。 定义自定义控件 ResourceDictionary 中的资源会对该控件的每个实例产生性能影响。 例如,如果将性能密集型画笔操作定义为自定义控件的资源定义的一部分和自定义控件的许多实例,则应用程序的工作集将显著增加。
若要说明这一点,请考虑以下事项。 假设你正在开发使用 WPF 的卡片游戏。 对于大多数纸牌游戏,你需要 52 张不同面孔的 52 张纸牌。 你决定实现卡片自定义控件,并在卡片自定义控件的资源中定义 52 个画笔(每个画笔代表卡片人脸)。 在主应用程序中,你最初创建此卡自定义控件的 52 个实例。 卡片自定义控件的每个实例生成 52 个 Brush 对象,这使得应用程序中的 Brush 对象总数达到 52 * 52 个。 通过将画笔从卡片自定义控件资源移到 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>