WPF资源

资源是WPF的一个重要主题,资源可以对一些属性值进行集中管理,方便后期统一修改和维护。WPF支持传统的二进制资源,也有特定的对象资源,本文进行系统介绍。

WPF对象资源

资源层次

ResourcesFrameworkElement类中定义的一个属性,而WPF中各种控件都是FrameworkElement的派生类,所以可在各种控件中定义资源。通常在窗体和应用程序的层次定义资源。

如果在不同层次上定义了资源,那么将沿着”控件→窗体→应用程序“的路径定位资源。

资源定义

资源可以是任何类的实例,可以使用XAML的语法对响应的属性进行赋值。但需要事先引入相应的命名空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<Window x:Class="TestResource.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestResource"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Loaded="Window_Loaded"
Title="MainWindow"
SizeToContent="WidthAndHeight">

<Window.Resources>
<sys:String x:Key="str1">欲望</sys:String>
<sys:Double x:Key="double1">3.1415926</sys:Double>
<SolidColorBrush x:Key="redBrush" Color='Red'/>
<SolidColorBrush x:Key="yellowBrush" Color='Blue'/>
<local:Student x:Key="student1" Name="李浩" Age="31" Motto="日积月累"/>
</Window.Resources>

<StackPanel x:Name="sp1" Orientation="Vertical">
<TextBlock Text="{Binding Source={StaticResource student1}, Path=Name}"
Foreground="{StaticResource redBrush}"/>
<TextBlock Text="{Binding Source={StaticResource student1}, Path=Age}"/>
<TextBlock Text="{Binding Source={StaticResource student1}, Path=Motto}"
Background="{StaticResource yellowBrush}"/>
</StackPanel>
</Window>

资源集合Resources

如上例所示,在<Window.Resources>中定义资源,只需要列出各资源即可,这实际上就是在构造ResourceDictionary,只不过可以省略该声明。

资源集合是定义窗体资源的最便利方式。如果想在多窗体或程序集之间复用资源,优先使用资源字典。

资源字典ResourceDictionary

创建

通过Visual Studio的项模板即可创建资源字典,形式如下,同资源集合一样可以添加各种资源:

1
2
3
4
5
6
7
8
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<sys:String x:Key="str1">欲望</sys:String>
<sys:Double x:Key="double1">3.1415926</sys:Double>
<SolidColorBrush x:Key="redBrush" Color='Red'/>
<SolidColorBrush x:Key="yellowBrush" Color='Blue'/>
</ResourceDictionary>

使用

通过以下方式引入即可,在此基础上也可以声明其它的资源:

1
2
3
4
5
6
7
8
<Window.Resources>
<ResourceDictionary>
<local:Student x:Key="student1" Name="李浩" Age="31" Motto="日积月累"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfControlLibrary1;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

这里的关键是如何给Source属性赋值:

  • 如果资源词典和引用资源词典的XAML文件在同一个项目,那么只需要给出相对路径即可。
  • 如果资源词典在其它程序集中,就需要注意写法/程序集名;component/资源词典路径
1
2
3
4
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfControlLibrary1;component/res/Dictionary1.xaml"/>
<ResourceDictionary Source="../Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>

系统资源

WPF为开发者提供了很多内置的资源,可以直接使用这些内置资源:SystemColorsSystemFontsSystemParameters

  • 方式1:可通过绑定静态变量的方式使用。

  • 方式2:通过动态资源的方式引用,每个SystemXxx都提供可返回ResourceKey对象引用的补充属性集。

1
2
<TextBox Text="明日复明日" Background="{x:Static SystemColors.ActiveBorderBrush}"/>
<TextBox Text="明日何其多" Background="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"/>

方式1无法动态修改属性,而方式2可以,这是两者最大的区别。

代码定位资源

使用FindResource()方法即可:

1
2
3
4
5
6
private void Window_Loaded(object sender, RoutedEventArgs e) {
var student = FindResource("student1") as Student;
if (student != null) {
MessageBox.Show($"Name={student.Name}");
}
}

动静之分

动态使用资源:{DynamicResource key},静态使用资源:{StaticResource key}

可以使用任何一种方式定位资源,区别在于动态使用资源可以在资源更新后动态刷新属性值,而静态使用资源不能做到这点。

传统二进制资源

MFC程序、WinForm程序等程序都可以添加二进制资源,基本原理就是把应用程序需要使用的资源和程序打包到一起,这样就不会意外丢失了。

常见的二进制资源包括:图标、图片、文本、音频、视频等,这些资源被打包到目标文件,以二进制形式存在,程序运行时可以动态提取使用。

向项目中添加.resx文件,在这个文件中可以添加字符串或者其它类型的资源。

最佳实践:在.resx文件中管理字符串资源;其它类型的资源以文件形式放在项目中,设置其生成操作为Resource,这样这些文件也会打包到目标文件,并且可以用最直观的方式对这些文件进行引用。

.resx文件中声明的资源会以资源类的静态只读属性呈现,按静态字段的方式即可访问:

1
2
3
4
5
internal static string String1 {
get {
return ResourceManager.GetString("String1", resourceCulture);
}
}

以文件形式定义的二进制资源,直接按照文件的方式进行访问即可:

1
2
3
<Image RenderOptions.BitmapScalingMode="NearestNeighbor" 
Stretch="None"
Source="pack://application:,,,/res/AI.jpg"/>
1
2
3
<Image RenderOptions.BitmapScalingMode="NearestNeighbor" 
Stretch="None"
Source="res/AI.jpg"/>

评论