优化性能:应用程序资源

WPF 允许共享应用程序资源,以便支持跨类似类型元素的一致性外观或行为。 本主题在此区域中提供了一些建议,可帮助你提高应用程序的性能。

有关资源的详细信息,请参阅 XAML 资源

共享资源

如果应用程序使用自定义控件并在 ResourceDictionary (或 XAML 资源节点)中定义资源,则建议在 ApplicationWindow 定义资源,也可以在自定义控件的默认主题中定义资源。 在自定义控件的 ResourceDictionary 中定义资源会对该控件的每个实例的性能产生影响。 例如,如果将性能密集型画笔操作定义为自定义控件的资源定义和许多自定义控件实例的一部分,则应用程序的工作集将显著增加。

为了说明这点,请考虑下列情况。 假设你正在使用 WPF 开发卡片游戏。 对于大多数卡片游戏,你需要 52 张具有 52 张不同牌面的卡片。 你决定实施卡片自定义控件,并在卡片自定义控件的资源定义 52 支画笔(每个画笔代表一个牌面)。 在主应用程序中,你最初创建此卡片自定义控件的 52 个实例。 卡片自定义控件的每个实例会生成 Brush 对象的 52 个实例,从而在应用程序中总共提供 52 * 52 Brush 个对象。 通过将画笔从卡片自定义控件资源移出到 ApplicationWindow 对象级别,或在自定义控件的默认主题中定义它们,可以减少应用程序的工作集,因为你现在正在卡片控件的 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>

另请参阅