UWP入门(六)-- ResourceDictionary 和 XAML 资源引用

简介: 原文:UWP入门(六)-- ResourceDictionary 和 XAML 资源引用 你最希望声明为 XAML 资源的 XAML 元素包括 Style、ControlTemplate、动画组件和 Brush 子类。
原文: UWP入门(六)-- ResourceDictionary 和 XAML 资源引用

你最希望声明为 XAML 资源的 XAML 元素包括 Style、ControlTemplate、动画组件和 Brush 子类。 我们在此处介绍

  • 如何定义 ResourceDictionary 和键控资源

  • XAML 资源与你定义为应用或应用包一部分的其他资源有何关系

  • 资源字典高级功能
    • MergedDictionaries
    • ThemeDictionaries。

1. 定义和使用 XAML 资源

<Page
    x:Class="SpiderMSDN.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
    <Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

所有资源都需要有一个键。 通常,键是通过 x:Key="myString" 定义的字符串。 但是,还有几种其他方法可指定键:

  • 如果未指定 x:Key,则 Style 和 ControlTemplate 需要 TargetType,并且将 TargetType 用作键。 在这种情况下,键是实际的 Type 对象,而非字符串。

  • 如果未指定 x:Key,具有 TargetType 的 DataTemplate 资源会将 TargetType 用作键。 在这种情况下,键是实际的 Type 对象,而非字符串。

  • x:Name 可以代替 x:Key 使用。 但是,x:Name 还会为资源生成代码隐藏字段。 因此,x:Name 的效率低于 x:Key,因为该字段需要在页面加载时进行初始化

StaticResource 标记扩展可以仅使用字符串名称(x:Key 或 x:Name)检索资源。 但是,XAML 框架在决定为尚未设置 Style 和 ContentTemplate 或 ItemTemplate 属性的控件使用哪个样式和模板时,还将查找隐式样式资源(使用 TargetType 而非 x:Key 或 x:Name 的资源)。

此处的 Style 具有隐式键 typeof(Button),并且由于页面底部的 Button 未指定 Style 属性,它将查找具有 typeof(Button) 键的样式:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button">
              <Setter Property="Background" Value="red"/>
        </Style>
    </Page.Resources> 
       <!-- This button will have a red background. -->
       <Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
</Page>

2. 查找代码中的资源

像任何其他字典一样,访问资源字典的成员

注意 当你执行在代码中查找资源的操作时,仅找到 Page.Resources 字典中的资源。 与 StaticResource 标记扩展不同,如果未在第一个字典中找到这些资源,该代码不会回退到 Application.Resources 字典

此示例演示如何在页面的资源字典中检索出 redButtonStyle 资源

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button" x:Key="redButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Page.Resources>
</Page>
public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
        }
    }

若要在代码中查找应用范围的资源,请使用 Application.Current.Resources 获取应用的资源目录,如下所示

<Application
    x:Class="MSDNSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SpiderMSDN">
    <Application.Resources>
        <Style TargetType="Button" x:Key="appButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Application.Resources>

</Application>
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
    }
}

以下是在执行此操作时要记住的两个事项:

  • 第一,在任何页面尝试使用资源时,你需要先添加资源。
  • 第二,不能在应用的构造函数中添加资源

如果在 Application.OnLaunched 方法中添加资源,可以避免这两个问题,如下所示

// App.xaml.cs

sealed partial class App : Application
{
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
        {
            SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
            this.Resources["brush"] = brush;
            // … Other code that VS generates for you …
        }
    }
}

3.每个 FrameworkElement 都可以具有 ResourceDictionary

FrameworkElement 是控件所继承的基类,并且具有 Resources 属性。 因此你可以将本地资源字典添加到任何 FrameworkElement

此时,资源字典已添加到页面元素

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <Border>
        <Border.Resources>
            <x:String x:Key="greeting">Hola mundo</x:String>
        </Border.Resources>
        <TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
    </Border>
</Page>

此时,Page 和 Border 都具有资源字典,并且都具有名为“greeting”的资源。 TextBlock 位于 Border 内,因此其资源查找将依次查找 Border 的资源、Page 的资源以及 Application 资源。 TextBlock 将读取“Hola mundo”

若要从代码访问元素的资源,请使用该元素的 Resources 属性。 在代码(而非 XAML)中访问 FrameworkElement 的资源,将仅在该字典中查找,而不在父级元素的字典中查找

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <Border x:Name="border">
        <Border.Resources>
            <x:String x:Key="greeting">Hola mundo</x:String>
        </Border.Resources>
    </Border>
</Page>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            string str = (string)border.Resources["greeting"];
        }
    }

4. 合并的资源字典(上一篇也有,简化版)

合并的资源字典将一个资源字典合并到通常在其他文件中的另一个字典

提示 可以在 Microsoft Visual Studio 中创建资源字典文件,方法是在项目菜单中依次使用add > new item…> dictionary recourse

此时,可以在名为 Dictionary1.xaml 的单独 XAML 文件中定义资源字典

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

若要使用该字典,请将它与页面的字典合并:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <x:String x:Key="greeting">Hello world</x:String>

        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

下面是本示例中会出现的结果。 在 <Page.Resources> 中,声明 <ResourceDictionary>。 当你向 <Page.Resources> 添加资源时,XAML 框架将为你隐式创建资源字典;但是在这种情况下,你需要的不仅是任一资源字典,你还需要包含合并字典的资源字典。

因此请声明 <ResourceDictionary>,然后将内容添加到其 <ResourceDictionary.MergedDictionaries> 集合。 其中每个条目都采用 <ResourceDictionary Source="Dictionary1.xaml"/> 形式。 若要添加多个字典,只需在第一个条目后添加 <ResourceDictionary Source="Dictionary2.xaml"/> 条目即可

<ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries> 后,你可以选择在主字典中放置其他资源。 你可以使用要合并到的字典中的资源,如同使用常规字典一样。 在上述示例中,{StaticResource brush} 在子级/合并字典 (Dictionary1.xaml) 中查找资源,而 {StaticResource greeting} 在主页字典中查找其资源

在资源查找序列中,仅在检查 ResourceDictionary 的所有其他键控资源后,才会检查 MergedDictionaries 字典。 搜索该级别后,查找会深入到合并后的字典,且对 MergedDictionaries 中的每一项进行检查。 如果存在多个合并的字典,会按在 MergedDictionaries 属性中声明这些字典的顺序的相反顺序来检查它们。 在以下示例中,如果 Dictionary2.xaml 和 Dictionary1.xaml 声明同一个键,则首先使用来自 Dictionary2.xaml 中的键,因为它排在 MergedDictionaries 集的末尾

在任一 ResourceDictionary 范围内,均会检查字典中键的唯一性。 但是,这一范围不会扩展到不同 MergedDictionaries 文件中的不同项

可以结合使用查找序列和跨合并字典范围不强制使用唯一键来创建 ResourceDictionary 资源的回退值序列。 例如,你可能会使用与应用的状态数据和用户首选项数据同步的资源词典,为序列中最后合并的资源字典中的特殊画笔颜色存储用户首选项。 但是,如果尚不存在任何用户首选项,则可为初始 MergedDictionaries 文件中的 ResourceDictionary 资源定义相同的键字符串,并可将其用作回退值。

请记住,始终会在检查合并字典之前检查你在主要资源字典中提供的任何值,所以如果希望使用回退技术,则不要在主要资源字典中定义该资源

5.主题资源和主题字典

ThemeResource 类似于 StaticResource,但资源查找会在主题更改时进行重新评估。

在此示例中,将 TextBlock 的前景设置为当前主题中的值

<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>

主题字典是一种特殊类型的合并字典,用于保存各种资源,具体资源取决于用户当前在其设备上使用的主题。 例如,“浅色”主题可能使用白色画笔,而“深色”主题可能使用黑色画笔。 画笔会更改它所溶入的资源,但使用该画笔作为资源的控件的组成可能保持不变。 若要在个人模板或样式中重现主题切换行为而不将 MergedDictionaries 用作属性以将项目合并到主词典中,请使用 ThemeDictionaries 属性

ThemeDictionaries 内的每个 ResourceDictionary 元素必须具有一个 x:Key 值。 该值是一个字符串,它为相关主题命名,例如 “Default”、“Dark”、“Light”或“HighContrast”。 通常,Dictionary1 和 Dictionary2 将定义名称相同但值不同的资源。

在此处,将红色文本用于浅色主题,蓝色文本用于深色主题

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

<!—Dictionary2.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="blue"/>

</ResourceDictionary>

在此示例中,将 TextBlock 的前景设置为当前主题中的值

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
                <ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    <TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>

对于主题字典,每当使用 ThemeResource 标记扩展进行引用并且系统检测到主题更改时,要用于资源查找的活动字典都会动态更改系统执行的查找行为基于将活动主题映射到特定主题字典的 x:Key 操作

检查主题字典在默认 XAML 设计资源中的构建方式十分有用,这些资源与 Windows 运行时默认用作其控件的模板相对应。 使用文本编辑器或 IDE 打开 \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic 中 的 XAML 文件。 请注意主题字典首先在 generic.xaml 中的定义方式,以及每个主题字典定义相同键的方式。 然后每个这样的键由构成各种键控元素的元素所引用,这些键控元素位于主题字典外部并且稍后在 XAML 中定义。 还存在用于设计的单独 themeresources.xaml 文件,该文件仅包含主题资源和额外模板,不包含默认控件模板。 这些主题区域是你将在 generic.xaml 中看到的内容副本。

当你使用 XAML 设计工具以编辑样式和模板的副本时,设计工具会提取 XAML 设计资源词典中的片段并将其作为应用和项目一部分的 XAML 字典元素的本地副本放置。

有关可用于应用的特定于主题的资源和系统资源的详细信息和列表,请参阅 XAML 主题资源

目录
相关文章
|
C# 前端开发
WPF中Style文件的引用——使用xaml代码或者C#代码动态加载
原文:WPF中Style文件的引用——使用xaml代码或者C#代码动态加载   WPF中控件拥有很多依赖属性(Dependency Property),我们可以通过编写自定义Style文件来控制控件的外观和行为,如同CSS代码一般。
4499 0
|
C#
WPF 添加 Resources Dictionary 资源 一般类库项目中无法添加资源文件(ResourceDictionary)
原文:WPF 添加 Resources Dictionary 资源 一般类库项目中无法添加资源文件(ResourceDictionary) 在文件夹或者项目右键-> Add(添加),会弹出可以快捷添加的资源,但是你会发现没有 ResourceDictionary资源可以选择。
3819 0
|
C#
艾伟_转载:WPF/Silverlight陷阱:XAML自定义控件的嵌套内容无法通过名称访问
为了说明这个问题,假定我们需要实现一个具有特殊功能的按钮控件。编写Xaml文件如下: Button> 对 Code Behind类,唯一的改动是把向导生成的基类从UserControl改成Button: public partial class XamlButton : Button{    ...
1046 0
|
C#
WPF在代码中创建DataTemplate时候的异常
原文:WPF在代码中创建DataTemplate时候的异常 今天写段程序用到了在代码中手动创建DataTemplate,     var factory = new FrameworkElementFactory(typeof(OperationColumn));    return new DataTemplate() { VisualTree = factory }; 运行的时候出现如下异常: FrameworkElementFactory 必须位于此操作的密封模板中。
890 0
|
C#
WPF中,怎样将XAML代码加载为相应的对象?
原文:WPF中,怎样将XAML代码加载为相应的对象? 在前面“在WPF中,如何得到任何Object对象的XAML代码?”一文中,我介绍了使用System.Windows.Markup.XamlWriter.Save(objName)得到任何Object对象的XAML代码。
888 0
|
C# .NET 开发框架
WPF笔记 ( xmlns引用,Resource、Binding 前/后台加载,重新绑定) 2013.6.7更新
原文:WPF笔记 ( xmlns引用,Resource、Binding 前/后台加载,重新绑定) 2013.6.7更新 1、xmlns Mapping URI的格式是 clr-namespace:[;assembly=] (1)如果自定义类和XAML处在同一个Assembly之中,只还需要提供clr-namespace值。
1396 0
|
C#
WPF整理-XAML访问静态属性
原文:WPF整理-XAML访问静态属性 "XAML provides an easy way to set values of properties—type converters and the extended property syntax allow for flexible setting of values.
929 0
|
前端开发 C# 程序员
WPF整理-XAML构建后台类对象
原文:WPF整理-XAML构建后台类对象 1.XAML 接触WPF的第一眼就是XAML---XAML是用来描绘界面的。其实不然! "Actually, XAML has nothing to do with UI. It's merely a declarative way of constructing objects and setting their properties.” XAML和UI一点关系也没有,它仅仅是一种以声明方式来构建对象,设置对象属性的一种方式而已,和code behind file作用差不多。
913 0
|
C# 前端开发 .NET
WPF中的资源简介、DynamicResource与StaticResource的区别
原文:WPF中的资源简介、DynamicResource与StaticResource的区别 什么叫WPF的资源(Resource)?资源是保存在可执行文件中的一种不可执行数据。在WPF的资源中,几乎可以包含图像、字符串等所有的任意CLR对象,只要对象有一个默认的构造函数和独立的属性。
1230 0
|
C# 前端开发
WPF 中style文件的引用
原文:WPF 中style文件的引用 总结一下WPF中Style样式的引用方法: 一,内联样式: 直接设置控件的Height、Width、Foreground、HorizontalAlignment、VerticalAlignment等属性。
919 0