25、Wpf之App资源应用

开发平台:Win10 64位

开发环境:VS2022(64位) Preview

.NET Framework:.NET 6


文章目录

  • [一 Resources](#一 Resources)
    • [1.1 Application中定义资源](#1.1 Application中定义资源)
    • [1.2 样式(Styles)](#1.2 样式(Styles))
    • [1.3 模板(Templates)](#1.3 模板(Templates))
    • [1.4 数据转换器(Converters)](#1.4 数据转换器(Converters))
    • [1.5 资源(Resources)](#1.5 资源(Resources))
  • [二 资源字典(ResourceDictionaries)](#二 资源字典(ResourceDictionaries))
    • [2.1 资源字典的两种定义方式](#2.1 资源字典的两种定义方式)
    • [2.2 使用资源字典](#2.2 使用资源字典)
  • 三、总结
  • 四、参考文献

一 Resources

wpf资源(Resources)是为了存储一系列我们常复用的对象,每个元素都有Resource属性。其实Resources的定义可以在每一个容器控件中(或者是在每一个控件,在Template 中可以用到),像C#中变量的定义一样,Resource的定义的地方不同决定它的作用范围,如:

  • Window.Resources它的作用范围就是在Window容器里的所有子控件有效,也只有这些子控件才能引用/调用这些资源
  • Grid.Resources它的作用范围就是在Grid容器里的所有子控件有效,也只有这些子控件才能引用/调用这些资源
    以此类推...

注意:Window不是最上层的"容器",最上层的应该是Appication ,所以Application.Resources 的作用范围更大(有人把Application.Resource叫作全局资源,所有在这个Application下的容器控件等都可以使用,常用来做一个应该程序的Skin ,其ResourceDictionary定义的资源也类似 )

1.1 Application中定义资源

本文以Application.Resources为例,Window和Grid等控件使用资源(Resources)属性和Application类似,可参考Application。

Application.Resources属性是一个非常有用的特性,它允许开发者在应用程序级别集中管理资源,如样式(Styles)、模板(Templates)、数据转换器(Converters)等。这有助于实现一致的设计风格,并且方便维护和更新。

  • 样式(Styles):样式(Styles):样式是一种资源,它定义了控件的外观和行为。样式可以应用于控件、元素、控件模板、数据模板、触发器、路由事件等。
  • 模板(Templates):模板(Templates):模板是一种资源,它定义了控件的结构和布局。模板可以应用于控件、元素、控件模板、数据模板、触发器、路由事件等。
  • 数据转换器(Converters):数据转换器是一种资源,它用于转换绑定源和目标之间的绑定值。
  • 资源(Resources):Resources属性是一种资源,它可以包含任意类型的值。
  • 资源字典(ResourceDictionaries):资源字典是一种资源,它可以包含多个样式、模板、数据转换器等资源。

下面是几种常用到的资源的在Application中的定义方式

1.2 样式(Styles)

样式(Styles)是一种资源,它定义了控件的外观和行为。样式可以应用于控件、元素、控件模板、数据模板、触发器、路由事件等。

xaml 复制代码
<Application.Resources>
    <Style x:Key="MyStyle" TargetType="Button">
        <Setter Property="Background" Value="Red" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontSize" Value="16" />
    </Style>
</Application.Resources>

1.3 模板(Templates)

模板(Templates)是一种资源,它定义了控件的结构和布局。模板可以应用于控件、元素、控件模板、数据模板、触发器、路由事件等。

xaml 复制代码
<Application.Resources>
    <DataTemplate x:Key="MyDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Name}" />
            <TextBlock Text="{Binding Age}" />
        </StackPanel>
    </DataTemplate>
</Application.Resources>

1.4 数据转换器(Converters)

数据转换器(Converters)是一种资源,它用于转换绑定源和目标之间的绑定值。

xaml 复制代码
<Application.Resources>
    <local:MyConverter x:Key="MyConverter" />
</Application.Resources>

1.5 资源(Resources)

Resources是一种资源,它可以包含任意类型的值。

xaml 复制代码
<Application.Resources>
    <Color x:Key="MyColor">Red</Color>
    <Thickness x:Key="MyThickness">10</Thickness>
    <FontFamily x:Key="MyFontFamily">Arial</FontFamily>
    <Style x:Key="MyStyle" TargetType="Button">
        <Setter Property="Background" Value="{StaticResource MyColor}" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontSize" Value="16" />
    </Style>
</Application.Resources>

以上几种方式定义的资源,都可以在XAML文件中使用,但是实际开发中没这么用的,一般都是放在资源字典中用,这样程序的可读写性更好。

二 资源字典(ResourceDictionaries)

2.1 资源字典的两种定义方式

资源字典(ResourceDictionaries)是一种资源,它可以包含多个样式、模板、数据转换器等资源。有两种定义方式:

  • 内联定义:在Application.Resources中定义资源字典,并在其中定义其他资源(style、模板、转换器等资源)。
xaml 复制代码
<Application.Resources>
    <ResourceDictionary>
        <Style x:Key="MyStyle" TargetType="Button">
            <Setter Property="Background" Value="Red" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="FontSize" Value="16" />
        </Style>
        <DataTemplate x:Key="MyDataTemplate">
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
                <TextBlock Text="{Binding Age}" />
            </StackPanel>
        </DataTemplate>
        <local:MyConverter x:Key="MyConverter" />
    </ResourceDictionary>
</Application.Resources>
  • 外部定义:在外部定义资源字典文件,并在Application.Resources中引用。

单独写一个样式资源字典文件(Styles.xaml)

xaml 复制代码
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="Background" Value="White" />
        <Setter Property="BorderBrush" Value="Gray" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Padding" Value="5" />
    </Style>
</ResourceDictionary>

然后在Application的资源中引用这个资源字典文件

xaml 复制代码
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

这样就可以在项目中使用ListBoxItem的样式了。

2.2 使用资源字典

因为资源字典定义在了Application中,因此在 XAML 文件中,可以通过控件的属性中设置资源的引用。

xaml 复制代码
<Button Content="Click Me" Style="{StaticResource MyStyle}" />
<DataTemplate x:Key="MyDataTemplate">
    <StackPanel>
        <TextBlock Text="{Binding Name}" />
        <TextBlock Text="{Binding Age}" />
    </StackPanel>
</DataTemplate>
<local:MyConverter x:Key="MyConverter" />
<Color x:Key="MyColor">Red</Color>
<Thickness x:Key="MyThickness">10</Thickness>
<FontFamily x:Key="MyFontFamily">Arial</FontFamily>

在上面的例子中,我们定义了三个资源:MyStyle、MyDataTemplate、MyConverter。然后在按钮的 Content 属性中引用了 MyStyle,在 DataTemplate 的 DataTemplate 属性中引用了 MyDataTemplate,在 local:MyConverter 的 Converter 属性中引用了 MyConverter,在 Color、Thickness、FontFamily 的值中引用了 MyColor、MyThickness、MyFontFamily。

三、总结

当多个资源具有相同的名称时,WPF 会按照以下优先级来确定资源的使用:

  • 样式(Styles)> 模板(Templates)> 数据转换器(Converters)> 资源字典(ResourceDictionaries)> 资源(Resources)

也就是说,如果有多个资源具有相同的名称,WPF 会按照样式、模板、数据转换器、资源字典、资源的顺序来确定使用哪个资源。

对于大型项目或者模块化开发,我们通常会把一些公共的样式、模板、数据转换器、资源字典等资源定义在单独的资源字典文件中,就是2.1中的外部定义方式,并通过引用的方式在项目中使用。这样可以避免资源的重复定义,提高代码的可维护性。比如我们会用到的控件样式,

在资源字典的使用中有些错误,下面是笔者遇到的

  • 内联方式:在Application.Resources中定义资源字典。
xaml 复制代码
<Application.Resources>
    <ResourceDictionary>
    	<Style x:Key="MyStyle" TargetType="Button">
        	<Setter Property="Background" Value="Red" /> 
    	</Style>
   	 	<DataTemplate x:Key="MyDataTemplate">
        	<StackPanel>
            	<TextBlock Text="{Binding Name}" />
            	<TextBlock Text="{Binding Age}" />
        	</StackPanel>
    	</DataTemplate>
    	<local:GenderConverter x:Key="GenderConverter" />
	</ResourceDictionary>
	<!--样式(Styles)-->
	<Style x:Key="MyStyle" TargetType="Button">
    	<Setter Property="Background" Value="Red" />
    	<Setter Property="Foreground" Value="White" />
    	<Setter Property="FontSize" Value="16" />
	</Style>
</Application.Resources>

把Style和ResourceDictionary换下位置

xaml 复制代码
<Application.Resources>
    <!--样式(Styles)-->
<Style x:Key="MyStyle" TargetType="Button">
    <Setter Property="Background" Value="Red" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="FontSize" Value="16" />
</Style>
<ResourceDictionary>
    <Style x:Key="MyStyle" TargetType="Button">
        <Setter Property="Background" Value="Red" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontSize" Value="16" />
    </Style>
    <DataTemplate x:Key="MyDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Name}" />
            <TextBlock Text="{Binding Age}" />
        </StackPanel>
    </DataTemplate>
    <local:GenderConverter x:Key="GenderConverter" />
</ResourceDictionary>
</Application.Resources>

需要给ResourceDictionary一个key值

复制代码
<ResourceDictionary x:Key="1">

这个时候是正常的,这个就是说,需要把资源字典(ResourceDictionary )放在其他的资源(style、模板、转换器等)的后面

个人观点:对于Application.Resources来说,styel、模板、转换器、资源字典都是一样的,所以需要像Style、DataTemplate一样添加key,不然在使用的时候没法区分是哪个资源字典

同时写两个即使填写了key也会报错,因为两个类型一样,就如同给Button控件设置了两次Content属性一样。但是在这两个ResourceDictionary 前面添加一个其他的资源(style、模板、转换器等),就不报错了,很费解。。。。。。

  • 引用外部定义的资源字典
    这个时候在Application.Resources节点下只写一个ResourceDictionary,没有style、模板、转换器等,且不对ResourceDictionary设置key
    如果设置了key就会报如下错误。去掉key="1"就可以了

    这样,<Application.Resources>下面只有一个节点,这个节点里面包含了其他资源。

    <Application.Resources>
    <ResourceDictionary >
    <Style x:Key="MyStyle" TargetType="Button">
    <Setter Property="Background" Value="Red" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="FontSize" Value="16" />
    </Style>
    <DataTemplate x:Key="MyDataTemplate">
    <StackPanel>
    <TextBlock Text="{Binding Name}" />
    <TextBlock Text="{Binding Age}" />
    </StackPanel>
    </DataTemplate>
    <local:GenderConverter x:Key="GenderConverter" />
    </ResourceDictionary>
    </Application.Resources>

进一步的引用外部定义的资源字典,这个结构是<Application.Resources>下面只有一个节点,这个节点里面除了包含style、模板、转换器等资源外还添加了外部资源字典,这个外部资源字典被合并到一起了,统一在<ResourceDictionary.MergedDictionaries>这个节点下面,和上面的不同点是<ResourceDictionary.MergedDictionaries>充当了Style、DataTemplate等资源的角色。

复制代码
<Application.Resources> 
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Secondary/MaterialDesignColor.Lime.xaml" />
            <ResourceDictionary Source="pack://application:,,,/BlankApp1;component/Res/Geometry.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/BlankApp1;component/Res/Style.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/BlankApp1;component/Res/Colors.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/BlankApp1;component/Res/DataGrid.xaml"/>
            <ResourceDictionary>
                <convert:VisibilityToInverseVisibilityConverter x:Key="InverseVisibility"/>
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
        <!--样式(Styles)-->
        <Style x:Key="MyStyle" TargetType="Button">
            <Setter Property="Background" Value="Red" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="FontSize" Value="16" />
        </Style>

        <!--模板(Templates)-->
        <DataTemplate x:Key="MyDataTemplate">
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
                <TextBlock Text="{Binding Age}" />
            </StackPanel>
        </DataTemplate>
        <!--数据转换器(Converters)-->
        <convert:VisibilityToInverseVisibilityConverter x:Key="InverseVisibility"/>

        <!--资源(Resources)-->
        <Color x:Key="MyColor">Red</Color>
        <Thickness x:Key="MyThickness">10</Thickness>
        <FontFamily x:Key="MyFontFamily">Arial</FontFamily>
    </ResourceDictionary>  
</Application.Resources>

四、参考文献

相关推荐
玖笙&2 天前
✨WPF编程基础【2.1】布局原则
c++·wpf·visual studio
玖笙&2 天前
✨WPF编程基础【2.2】:布局面板实战
c++·wpf·visual studio
SEO-狼术2 天前
.NET WPF 数据编辑器集合提供列表框控件
.net·wpf
FuckPatience6 天前
WPF 具有跨线程功能的UI元素
wpf
诗仙&李白6 天前
HEFrame.WpfUI :一个现代化的 开源 WPF UI库
ui·开源·wpf
He BianGu6 天前
【笔记】在WPF中Binding里的详细功能介绍
笔记·wpf
He BianGu6 天前
【笔记】在WPF中 BulletDecorator 的功能、使用方式并对比 HeaderedContentControl 与常见 Panel 布局的区别
笔记·wpf
123梦野7 天前
WPF——效果和可视化对象
wpf
He BianGu7 天前
【笔记】在WPF中Decorator是什么以及何时优先考虑 Decorator 派生类
笔记·wpf
时光追逐者8 天前
一款专门为 WPF 打造的开源 Office 风格用户界面控件库
ui·开源·c#·.net·wpf