什么叫WPF的资源(Resource)?
资源是保存在可执行文件中的一种不可执行数据。在WPF的资源中,几乎可以包含图像、字符串等所有的任意CLR对象,只要对象有一个默认的构造函数和独立的属性。也就是说,应用程序中非程序代码的内容,比如点阵图、颜色、字型、动画/影片档以及字符串常量值,可将它们从程序中独立出来,单独包装成"资源(Resource)"。
资源是可以在应用程序的不同位置重用的对象。XAML资源的示例包括画笔和样式。每个框架级别的元素(FrameworkElement或FrameworkContentElement)都有一个resources属性(集合),该属性包含资源定义的资源(作为ResourceDictionary)。可以在任何元素上定义资源,但是资源通常是在根元素上定义的。当在页面根元素上定义一个资源时,页面逻辑树中的所有元素都可以访问它,并且您可以重用相同的资源来设置接受该资源表示的类型的任何属性的值。
可以将资源引用为静态资源或动态资源。这可以通过使用StaticResource标记扩展或DynamicResource标记扩展来实现。通过替换已定义资源的值,StaticResource为属性提供了一个值,DynamicResource将属性值延迟为资源的运行时引用,从而为属性提供一个值。动态资源引用在每次访问此类资源并在运行时访问对象图时强制执行新的查找。为了获得这种访问,WPF属性系统中的依赖属性支持DynamicResource概念,并计算表达式。因此,只能对依赖项属性目标使用DynamicResource。
所有的资源项在最终都会被整合到Resource Dictionary中的,也就是说无论是FrameworkElement的Resources,还是Window的Resources,还是Application的Resources,还是特定的ResourceDictionary中定义的resources在整个应用编译执行的时候实际上他们都在一起的作为可遍历集合共同存在于一个相对会话空间内的。 我们也提到过Resource的key是可以被允许有相同的,这样在遍历不同相对地址的Resource Dictionary时会根据StaticResource或者DynamicResource的lookup behavior来确定哪个有效。通常为了维护和灵活性的考虑,我们通常会将Resource Dictionary文件分成好几个,但在某些场合下我们只需要用其中某些资源,那么我么可以将资源从几个独立的文件中提取并合并。
资源的范围(层级):
资源应用域
WPF提供一个封装和存取资源(resource)的机制,我们可将资源建立在应用程序的不同范围上。WPF中,资源定义的位置决定了该资源的可用范围。资源可以定义在如下范围中:
(1)物件级:此时,资源只能套用在这个Object物件,或套用至该物件的子物件。
(2)文件级:如果将资源定义在Window或Page层级的XAML档中,那么可以套用到这个文件中的所有物件。
(3)应用程序级:如果我们将资源定义在App.xaml 中,那么,就可以将资源套用到应用程序内的任何地方。
(4)字典级:当我们把资源封装成一个资源字典, 定义到一个ResourceDictionary的XAML文件时,就可以在另一个应用程序中重复使用。
每一个框架级元素( FrameworkElement 或者 FrameworkContentElement )都有一个资源属性。每一个在资源字典中的资源都有一个唯一不重复的键值(key),在标签中使用x:Key属性来标识它。一般地,键值是一个字符串,但你也可以用合适的扩展标签来设置为其他对象类型。非字符键值资源使用于特定的WPF区域,尤其是风格、组件资源,以及样式数据等。
引用方式
引用资源 静态引用资源 和动态引用资源
资源不仅可以在XAML代码中访问,也可以使用C#代码访问和控制它们。方法是使用FindResource查找资源,Resource.Add增加资源和Resource.Remove(移除资源)。
StaticResource 查询行为不支持向前引用,即不能引用在引用点之后才定义的资源。而DynamicResource可以向前引用,即DynamicResource运行时才查找并加载所定义的资源。
注意:
Windows8应用中,XAML资源仅支持StaticResource(静态资源);
资源应用域不同,XAML资源可分为FrameworkElement.Resources和 Application.Resources
FrameworkElement.Resources是将资源对象应用于同一个对象数的不同对象上,称之为页面资源,通常被定义在XAML页面根元素上。
Application.Resources是贯穿整个应用级别的资源,通常被定义在App.xaml页面
FrameworkElement.Resources(页面资源):前面已经举例,这里就不详述。
Application.Resourcess(贯穿整个应用级别的资源)
静态资源字典引用方式如下:
<TextBlock Text="{StaticResource ResourceKey=balck}" /> 或者 //ResourceKey 是内容属性,可以省略不写 <TextBlock Text="{StaticResource balck}" />
DynamicResource将属性值延迟为资源的运行时引用,从而为属性提供一个值。动态资源引用在每次访问此类资源并在运行时访问对象图时强制执行新的查找。为了获得这种访问,WPF属性系统中的依赖属性支持DynamicResource概念,并计算表达式。因此,只能对依赖项属性目标使用DynamicResource。
使用ComponentResourceKey时 ,必须使用 DynamicResource ,例如在程序集间使用资源字典共享资源时候,就必须使用DynamicResource
控件查找资源的顺序 1》2》3》4
在基本控件中都有resources这个属性,该属性是个集合类型,支持索引,而且查询资源的时候,会先从本控件开始找,然后一层层向上,最后会到达application的资源,
<Window x:Class="DP.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:DP" xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:hc="https://handyorg.github.io/handycontrol" mc:Ignorable="d" Name="ThisWin" Title="MainWindow" Height="450" Width="800"> <Grid> <Label Content="{DynamicResource NBam}"> <Label.Resources> <sys:String x:Key="NBam" >颜色</sys:String> </Label.Resources> </Label>
窗体页面的根。可以在任何元素上定义资源,但是资源通常是在根元素上定义的。当在页面根元素上定义一个资源时,页面逻辑树中的所有元素都可以访问它,并且您可以重用相同的资源来设置接受该资源表示的类型的任何属性的值。
<Window x:Class="DP.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:DP" xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:hc="https://handyorg.github.io/handycontrol" mc:Ignorable="d" Name="ThisWin" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <sys:String x:Key="NBam" >颜色</sys:String> </Window.Resources> <Grid> <Label Content="{StaticResource NBam}"></Label> </Grid> </Window>
资源字典的作用
主要原因有两个:
<Application x:Class="DP.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:DP" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!--将以下的资源字典 归并道app.xaml 字典中一起编译成baml--> <!--务必将app.xaml和以下的资源字典都设置成生成操作 bulid action--> <ResourceDictionary Source="Dirctionary/colour.xaml"/> <ResourceDictionary Source="Dirctionary/Skin.xaml"/> </ResourceDictionary.MergedDictionaries> <local:ChineseNumToNumberConvert x:Key="ChineseNumToNumberConvertKey"/> </ResourceDictionary> </Application.Resources> </Application>
colour.xaml 代码如下
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard" > <sys:String x:Key="balck" >黑色</sys:String> <sys:String x:Key="wihte" >白色</sys:String> <sys:String x:Key="blue" >蓝色</sys:String> </ResourceDictionary>
Skin.xaml代码如下
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard" > <sys:String x:Key="autumn" >秋天</sys:String> <sys:String x:Key="spring" >春天</sys:String> <sys:String x:Key="winter" >冬天</sys:String> </ResourceDictionary>
应用 代码如下:
<Window x:Class="DP.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:DP" xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:hc="https://handyorg.github.io/handycontrol" mc:Ignorable="d" Name="ThisWin" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="60*"></RowDefinition> <RowDefinition Height="60*"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel Orientation="Vertical" Grid.Row="0"> <Label>中文数字</Label> <TextBox x:Name="wc1">一</TextBox> <TextBox x:Name="wc2">二</TextBox> <TextBox x:Name="wc3">三</TextBox> </StackPanel> <StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="1"> <Label>英文数字</Label> <TextBox Text="{Binding ElementName=wc1,Path=Text, Converter={StaticResource ResourceKey=ChineseNumToNumberConvertKey}}"></TextBox> <TextBox Text="{Binding ElementName=wc2,Path=Text, Converter={StaticResource ResourceKey=ChineseNumToNumberConvertKey}}"></TextBox> <TextBox Text="{Binding ElementName=wc3,Path=Text, Converter={StaticResource ResourceKey=ChineseNumToNumberConvertKey}}"></TextBox> </StackPanel> <StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="0"> <Label>颜色</Label> <TextBlock Text="{StaticResource ResourceKey=balck}" /> <TextBlock Text="{StaticResource ResourceKey=wihte}" /> <TextBlock Text="{StaticResource ResourceKey=blue}" /> </StackPanel> </Grid> </Window>
框架dll文件中的资源(意味可以自定义 dll文件,并且引用此文件)
主要存在system命名空间中, SystemFonts 字体类、SystemColors 颜色类、SystemParameters 参数类(键盘 、屏幕、鼠标大小等设置、以及图形的效果(阴影 拖动等))。
(1)创建
首先是共享资源的创建,创建一个新的“wpf自定义控件”项目,然后随便添加一个图片作为示例资源。
文件结构如下:
资源字典文件(background.xaml)里面的代码如下:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ResourceLiarary" > <ImageBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:CustomControl1},ResourceId=test}" ImageSource="pack://application:,,,/ResourceLiarary;component/Snipaste.png"></ImageBrush> </ResourceDictionary>
因为这个资源是要作为共享资源的,所以这里要使用绝对 pack URI路径
(2)资源配置
1.资源合并
如果你创建了多个资源字典作为共享资源的话,进行资源合并就是必须的,资源合并的代码写在Generic.xaml里:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ResourceLiarary" > <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/ResourceLiarary;component/background.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>
这里的重点也和上面一样,要使用绝对url路径
2.类文件
这一步其实可以是可选的,但加上之后可以简化资源的使用,因此也是用必要的
public class CustomControl1 { public static ComponentResourceKey test { get { return new ComponentResourceKey(typeof(CustomControl1), "test"); } } }
3、将图片设置为“资源” ,就会将图片嵌入程序集中,方便引用。
(3)、编译生成 组件“ResourceLiarary.dll”
(4)、在新项目中引入该com组件“ResourceLiarary.dll”
(5) xaml 命名空间引入ResourceLiarary
(6)xaml 代码引入ResourceLiarary 命名空间
<Button Background="{DynamicResource {x:Static res:CustomControl1.test}}" >
<Window x:Class="DP.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:DP" xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:res="clr-namespace:ResourceLiarary;assembly=ResourceLiarary" mc:Ignorable="d" Name="ThisWin" Title="MainWindow" Height="450" Width="800"> <Grid> <Button Background="{DynamicResource {x:Static res:CustomControl1.test}}" > </Button> </Grid> </Window>
res:CustomControl1.test 是ComponentResourceKey 所以必须使用 DynamicResource