资源是WPF的一个重要主题,资源可以对一些属性值进行集中管理,方便后期统一修改和维护。WPF支持传统的二进制资源,也有特定的对象资源,本文进行系统介绍。
WPF对象资源
资源层次
Resources
是FrameworkElement
类中定义的一个属性,而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为开发者提供了很多内置的资源,可以直接使用这些内置资源:SystemColors
、SystemFonts
、SystemParameters
。
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"/>
|