WPF之资源

在 XAML 中使用的资源

下面的示例定义SolidColorBrush作为页面的根元素上的资源。 该示例然后引用的资源,并使用它来设置属性的多个子元素,其中包括椭圆、 TextBlock,和一个按钮。

<Page Name="root"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
  <Page.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
    <Style TargetType="Border" x:Key="PageBackground">
      <Setter Property="Background" Value="Blue"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="TitleText">
      <Setter Property="Background" Value="Blue"/>
      <Setter Property="DockPanel.Dock" Value="Top"/>
      <Setter Property="FontSize" Value="18"/>
      <Setter Property="Foreground" Value="#4E87D4"/>
      <Setter Property="FontFamily" Value="Trebuchet MS"/>
      <Setter Property="Margin" Value="0,40,10,10"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="Label">
      <Setter Property="DockPanel.Dock" Value="Right"/>
      <Setter Property="FontSize" Value="8"/>
      <Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
      <Setter Property="FontFamily" Value="Arial"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Margin" Value="0,3,10,0"/>
    </Style>
  </Page.Resources>
  <StackPanel>
    <Border Style="{StaticResource PageBackground}">
      <DockPanel>
        <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
        <TextBlock Style="{StaticResource Label}">Label</TextBlock>
        <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
        <Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
        <Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
      </DockPanel>
    </Border>
  </StackPanel>
</Page>

每个框架级元素 ( FrameworkElement或FrameworkContentElement) 具有资源属性,它是包含资源的属性 (作为ResourceDictionary) 资源定义。 您可以在任何元素上定义的资源。 但是,在根元素,它是最常定义资源页在示例中。
定义的资源后,你可以引用要使用的属性值,通过使用指定键的名称,例如资源标记扩展语法的资源︰

      <Button Background="{StaticResource MyBrush}"/>
      <Ellipse Fill="{StaticResource MyBrush}"/>

在前面的示例中,当XAML加载器处理值{StaticResource MyBrush}为背景属性按钮,资源查找逻辑首先检查资源字典中的是否按钮元素。 如果按钮没有一个定义的资源键MyBrush(不是,其资源集合为空),查找接下来检查的父元素按钮,即页。 因此,当您定义的资源上页根元素中,在逻辑树中的所有元素页可以访问它,并为任何属性的值设置接受,您可以重复使用同一资源类型该资源表示。 在上一示例中,相同MyBrush资源设置两个不同的属性︰背景的按钮,和填充的矩形。

静态和动态资源

可以作为静态资源或动态资源引用资源。 这通过使用StaticResource 标记扩展或DynamicResource 标记扩展。 标记扩展是一项功能的XAML,您可以通过使用标记扩展来处理特性字符串并返回到对象中指定的对象引用由此XAML加载程序。 有关标记扩展行为的详细信息,请参阅标记扩展和 WPF XAML。
当您使用的标记扩展时,您通常会提供一个或多个参数采用字符串形式,由该特定标记扩展,处理,而不是所设置的属性的上下文中进行求值。 StaticResource 标记扩展处理通过查找所有可用的资源字典中的键的值的键。 发生这种情况在加载期间,它是在加载过程需要分配采用静态资源引用的属性值的时间内的点。 DynamicResource 标记扩展改为进程通过创建一个表达式,并且该表达式的键会一直保持未计算直到实际运行该应用程序,在这段时间的表达式进行计算和属性提供值。
在引用某个资源时,无论是使用静态资源引用还是动态资源引用可以影响下列注意事项︰

  • 如何为您的应用程序创建资源的整体设计 (每页上,在应用程序中,在松散XAML,资源的唯一程序集中)。

  • 应用程序功能︰ 正在更新的应用程序的要求的实际时间部分中的资源?

  • 该资源的引用类型的相应查找行为。
  • 特定属性或资源类型以及这些类型的本机行为。
静态资源

静态资源引用最适合于以下情况︰

  • 应用程序设计中最重要的是其资源集中到页或应用程序级别资源的集中字典。
    静态资源引用不会重新计算基于运行时行为,如重新加载页,并且因此可以在不需要每个资源和应用程序设计时避免大量动态资源引用的某些性能优势。
  • 正在设置不在属性的值DependencyObject或Freezable。

  • 正在创建的资源字典,将编译成 DLL,并打包为应用程序的一部分或应用程序之间共享。

  • 要创建自定义控件的主题,并且定义在主题中使用的资源。 这种情况下,您通常不希望动态资源引用查找行为,以便查找可预测并且是独立的主题,你会转而考虑静态资源引用行为。 使用动态资源引用,甚至是主题中的引用进行求值直到运行时,并且没有应用主题时,某个本地元素会重新定义的键,您的主题试图引用,并且本地元素会位于主题本身在查找中之前有机会。 如果发生这种情况,您的主题不在预期的方式中的行为。
  • 正在使用资源来设置大量的依赖项属性。 依赖项属性具有有效值缓存为启用的属性系统,因此,如果依赖项属性可提供的值在加载时,计算依赖项属性而不必重新求值表达式检查并且可以返回的最后一个有效的值。 此方法可以提高性能。
  • 你想要为所有使用者,更改基础资源或者你想要使用的每个使用者维护单独的可写实例x︰ 共享属性。
动态资源

动态资源最适合于在下列情况︰

  • 资源的值取决于直到运行时才知道的条件。 这包括系统资源或用户可设置的资源。 例如,创建参考系统属性的 setter
    值公开SystemColors, SystemFonts,或SystemParameters。
    这些值是真正的动态的因为它们最终来自用户和操作系统的运行时环境。 您还可能会发生变化,其中页级别的资源访问还必须捕获更改的应用程序级主题。
  • 要创建或引用的自定义控件的主题样式。
  • 你想要调整的内容ResourceDictionary在应用程序生存期内。
  • 必须具有相互依赖关系前, 向引用可能要求复杂的资源结构。 静态资源引用不支持前向引用,但动态资源引用支持,因为不需要在运行时以前, 计算资源前, 向引用因此彼此不相关的概念。
  • 引用是从编译或工作集的角度来看特别大的资源和资源可能不会立即加载页面时使用。 静态资源引用始终从加载XAML加载页面时; 但是,动态资源引用不会加载直到它被实际使用。
  • 要创建 setter 值可能来自其他受主题或其他用户设置的值的样式。
  • 正在将资源应用于应用程序生命周期内可能会在逻辑树中父级的元素。 也有可能更改父站点更改资源查找范围,因此如果您希望为设置了父级的元素将会重新计算资源基于新的作用域,始终使用动态资源引用。
限制

动态资源引用具有一些重要的限制。 至少一个以下必须满足︰
要设置的属性必须是属性上FrameworkElement或FrameworkContentElement。 属性必须为后盾DependencyProperty。
引用是对中的一个值样式Setter。
要设置的属性必须是属性上Freezable作为其中任何一个值提供FrameworkElement或FrameworkContentElement属性,或Setter值。
由于所设置的属性必须是DependencyProperty或Freezable属性,属性的大多数更改可以传播到 UI,因为属性更改 (更改的动态资源值) 时确认了属性系统。 大多数控件包含逻辑,用于将强制另一个控件布局,如果DependencyProperty更改和属性可能会影响布局。 但是,并非所有属性都具有DynamicResource 标记扩展作为其值保证提供这种方式中用户界面中的实时更新中的值。 该功能仍可能会有所不同的具体取决于该属性,以及根据所拥有的属性或甚至您的应用程序的逻辑结构的类型。

样式、 Datatemplate 和隐式键

前面曾提到中的所有项ResourceDictionary必须具有一个键。 但是,也不表示所有资源必须都具有一个显式x:Key。 多个对象类型都支持隐式键时定义为资源,其中的密钥值绑定到另一个属性的值。 这称为隐式键,而x:Key属性是显式的键。 您可以通过指定显式键覆盖任何隐式键。
资源的一个非常重要的方案是在定义时样式。 事实上,样式几乎始终定义为将项记入资源字典中,因为样式本质上是适合于重复使用。 有关样式的详细信息,请参阅样式和模板化。
控件样式可同时创建和使用隐式键引用。 定义控件的默认外观的主题样式依赖于此隐式键。 从请求该的角度来看,隐式键是类型控件本身。 从定义该资源的角度来看,隐式键是TargetType的样式。 因此,如果要创建自定义控件的主题,创建的样式的交互与现有主题样式,您不必指定X:key 指令为此,样式。 而且,如果您想要使用的主题的样式,不需要在所有指定的任何样式。 例如,下面的样式定义的工作原理,即使样式资源似乎不具有键︰

<Style TargetType="Button">
      <Setter Property="Background">
        <Setter.Value>
          <LinearGradientBrush>
            <GradientStop Offset="0.0" Color="AliceBlue"/>
            <GradientStop Offset="1.0" Color="Salmon"/>           
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>  
      <Setter Property="FontSize" Value="18"/>
    </Style>

该样式实际上具有一个键︰ 隐式键typeof(按钮)。 在标记中,您可以指定TargetType直接作为类型名称 (或您可以选择使用{x︰ 类型…} 若要返回类型。
DataTemplate还具有隐式键。 隐式键DataTemplate是DataType属性值。 数据类型也可以指定为的类型的名称,而不是使用显式{x︰ 类型…}. 有关详细信息,请参阅数据模板化概述。

从代码访问资源

如果标识资源的键是通过 XAML 定义的,则这些键也用于当您在代码中请求资源时检索特定资源。 从代码检索资源的最简单方法是从应用程序中的框架级对象调用 FindResource 或 TryFindResource 方法。 这两个方法之间的行为差异在于当未找到所请求的键时所发生的情况。 FindResource 引发异常;TryFindResource 不引发异常,而是返回 null。 每个方法都将资源键作为一个输入参数,并返回一个松散类型的对象。 资源键通常是字符串,但有时也使用非字符串;有关详细信息,请参见将对象用作键部分。 通常应将返回的对象强制转换为请求资源时设置的属性所要求的类型。 代码资源解决方案的查找逻辑与动态代码引用 XAML 情况相同。 搜索资源从调用元素开始,然后继续搜索逻辑树中的后续父元素。 如果必要,查找将继续向应用程序资源、主题以及系统资源进行。 资源的代码请求将正确地说明资源字典(可能排在从 XAML 加载的资源字典之后)中的运行时更改,也将说明实时系统资源更改。
下面是一段简短的代码示例,该示例按键查找资源并使用返回的值来设置属性,该示例是作为 Click 事件处理程序实现的。

void SetBGByResource(object sender, RoutedEventArgs e)
{
  Button b = sender as Button;
  b.Background = (Brush)this.FindResource("RainbowBrush");
}

分配资源引用的另一种方法是 SetResourceReference。 该方法采用两个参数:资源的键,以及特定依赖项属性(属于资源值要赋予的元素实例)的标识符。 此方法在功能上是相同的,且具有无需强制转换任何返回值的优点。
还有另一种以编程方式访问资源的方法,即:将 Resources 属性的内容作为字典来访问。 通过访问该属性包含的字典,还可以向现有集合中添加新资源、检查集合中是否已经存在给定的键名称以及执行其他字典/集合操作。 如果完全以代码编写 WPF 应用程序,则也可以通过代码创建整个集合,为其指定键,然后将完成的集合指定给已建立的元素的 Resources 属性。 这将在下一部分介绍。
可以在任何给定的 Resources 集合内编制索引(将特定键用作索引),但您应当知道以这种方式访问资源不遵循资源解决方案的常规运行时规则。 您访问的仅是该特定集合。 如果在请求的键处未找到有效的对象,则资源查找将不会遍历范围直至根或应用程序。 但是,在某些情况下,正因为对键的搜索范围进行了更多的约束,才使得此方法在性能上具有优势。 有关如何直接处理资源字典的更多详细信息,请参见 ResourceDictionary 类。

使用代码创建资源

如果要以代码创建整个 WPF 应用程序,您可能也需要以代码创建该应用程序中的任何资源。 要实现此目的,应当先新建一个 ResourceDictionary 实例,然后使用对 ResourceDictionary.Add 的连续调用将所有资源添加到字典中。 然后使用最终创建的 ResourceDictionary 来设置位于页范围内的元素的 Resources 属性,或设置 Application.Resources 的属性。 您也可以将 ResourceDictionary 作为一个单独的对象来维护(而不将它添加到元素中)。 但是,如果这样,则您必须按项键来访问其中的资源,就好像它是泛型字典一样。 未附加到元素的 Resources 属性的 ResourceDictionary 将不作为元素树的一部分存在,在查找序列中也不具有可供 FindResource 及相关方法使用的范围。

将对象用作键

大多数资源用法都会将资源的键设置为字符串。 但是,各个 WPF 功能都特意不使用字符串类型来指定键,而是将此参数设置为对象。 WPF 样式和主题支持使用按对象对资源进行键控的功能。 主题中成为非样式控件的默认样式的样式都将按它们要应用于的控件的 Type 来进行键控。 按类型进行键控提供了一种可靠的查找机制,该机制作用于每个控件类型的默认实例,即使派生类型不具有默认样式,也可以通过反射检测到类型,并将类型用于设置派生类的样式。 可以使用 x:Type 标记扩展为 XAML 中定义的资源指定 Type 键。 对于支持 WPF 功能的其他非字符串键用法,也存在类似扩展,如 ComponentResourceKey 标记扩展。

合并资源字典

Windows Presentation Foundation (WPF)资源支持合并的资源字典功能

引入了合并的资源字典

在标记中,你可以使用以下语法将合并的资源字典引入到页面︰

<Page.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="myresourcedictionary.xaml"/>
        <ResourceDictionary Source="myresourcedictionary2.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Page.Resources>

请注意, ResourceDictionary元素不具有X:key 指令,这是通常所必需的资源集合中的所有项。 但另一个ResourceDictionary内引用MergedDictionaries集合是一种特殊情况,留待此合并的资源字典方案。 ResourceDictionary引入了合并资源字典中不能有X:key 指令。 通常情况下,每个ResourceDictionary内MergedDictionaries集合指定源属性。 值源应统一资源标识符 (URI)可解析为要合并的资源文件的位置。 该目标URI必须是另一个XAML文件中,与ResourceDictionary作为其根元素。
合并的字典的行为
合并的字典中的资源占用恰好在它们被合并到主资源字典中的作用域之后资源查找范围中的位置。 尽管资源键必须是在任何字典中是唯一的存在的密钥可以多次一对合并的字典。 在这种情况下,则返回该资源将来自按顺序在找到的最后一个字典MergedDictionaries集合。 如果MergedDictionaries集合中定义XAML,则集合中合并的字典的顺序是元素的顺序,在标记中所述。 如果主字典和一个字典,其中进行了合并,则未定义键,则返回该资源将来自主字典。 这些范围规则同样适用为静态资源引用和动态资源引用。

合并的字典和代码

合并的字典可以添加到Resources通过代码的字典。 默认情况下,最初为空ResourceDictionary存在任何Resources属性都具有默认值,最初为空MergedDictionaries集合属性。 若要添加的代码通过合并的字典,则获取到所需的主副本的引用ResourceDictionary,获取其MergedDictionaries属性值,然后调用Add泛型Collection中包含MergedDictionaries。 您添加的对象必须是一个新ResourceDictionary。 在代码中,您没有设置源属性。 相反,你必须获取ResourceDictionary通过创建一个,或者加载其中一个对象。 加载现有值的一种方法ResourceDictionary调用XamlReader.Load在现有XAML具有文件流ResourceDictionary根,然后转换XamlReader.Load返回值为ResourceDictionary。

合并的资源字典 Uri

有几种技术来包括合并的资源字典,这由统一资源标识符 (URI)将使用的格式。 概括地说,这些技术可以分为两个类别︰ 作为项目的一部分,编译的资源和不项目的一部分作为编译的资源。
对于编译为项目的一部分的资源,可以使用引用的资源位置的相对路径。 相对路径是在编译期间计算的。 所需的资源必须定义为资源生成操作作为项目的一部分。 如果在项目中作为资源包括资源.xaml 文件,不需要将资源文件复制到输出目录,该资源已包含在编译的应用程序。 此外可以使用内容的生成操作,但您必须再将文件复制到输出目录,并还将相同路径关系中的资源文件部署到可执行文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LADT-LINZI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值