WPF Resource资源
来源:程序员人生 发布时间:2015-04-20 08:34:17 阅读次数:3914次
WPF不但支持程序级的传统资源,同时还推出了独具特点的对象级资源,每一个界面元素都可以携带自己的资源并可被自己的子级元素同享。比如后面的章节我们会讲到模板、程序样式和主题就常常放在对象资源里面。这样1来,在WPF程序中数据就分为4个等级存储了:数据库里的数据相当于寄存在仓库里面,资源文件里的数据就相当于放进了旅行箱里,WPF对象资源里面的数据相当于寄存在携带的背包里,变量里面的数据相当于拿在手里。
1. WPF对象资源的定义和查找
每一个WPF界面元素都有1个名为Resource的属性,这个属性继承至FrameworkElement类,其类型为ResourceDictionary。ResourceDictionary能够以键值对的情势存储资源,当要使用到某个资源的时候,使用键值对的情势获得资源对象。在保存资源时,ResourceDictionary视资源对象为Object类型,所以再使用资源时先要对资源对象进行类型转换,XAML编译器能够根据Attribute自动辨认资源类型,如果类型不对就会抛出异常,但在C#中检索到资源对象以后,类型转换的事情就只能由我们自己来做了。ResourceDictionary可以存储任意类型的对象。在XAML代码中向Resource添加资源时需要把正确的命名空间引入到XAML代码中,让我们来看1个例子:
<Window x:Class="WpfApplication10.wnd101"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="120" Width="525">
<Window.Resources>
<ResourceDictionary>
<sys:String x:Key="_str">字符串</sys:String>
<sys:Double x:Key="_db">89.7898</sys:Double>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<!--C#中可使用FindResource查找对象资源-->
<TextBlock x:Name="_txtBlock" FontSize="16" Text="{StaticResource ResourceKey=_str}" Height="28"/>
</StackPanel>
</Window>
首先我们将System命名空间引入XAML代码中并映照为sys名称空间,然后在Windows.Resource里面添加了两个资源条目,1个是string类型,1个是double类型。最后我们用textBlock来消费这个资源。程序运行效果以下图:
查找资源时,先查找控件自己的Resource属性,如果没有这个资源程序会沿着逻辑树向上1级进行查找,如果连最顶端容器都没有这个资源,程序就会查找Application.Resource(也就是程序的顶级资源)。如果还没有找到,那末就只能抛出异常了。
这就好比每一个界面元素都有自己的1个背包,里面可能装有各种各样的资源,使用的时候打开找1找,如果没有找到还可以去翻看上1层控件的背包,直至找到这个资源或报告没有这个资源为止。
你可能会想,如果把资源像CSS或JS1样放在独立的文件夹里,使用时成套援用、重用时便于分发岂不更好?WPF的资源固然可以做到这1点;ResourceDictionary具有1个名为Source的属性,只要把包括资源定义的文件路径赋值给这个属性就1切弄定了!例如把皮肤以资源的情势放在XAML文件中,使用时仅需要将相应的XAML文件添加进项目并使用Source属性进行援用,你的程序就立刻变的鲜明照人。
<Window.Resources>
<!--用于1键换肤-->
<ResourceDictionary Source="ShinyRed.xaml"></ResourceDictionary>
</Window.Resources>
2. 且“动”且“静”用资源
当资源被存储进资源词典以后,我们可使用两种方式来使用这些资源-----静态方式和动态方式。静态资源使用StackResource指的是程序载入内存时对资源的1次性使用,以后就不在去访问这个资源了;动态资源(DynamicResource)使用指的是在程序运行进程中依然会去访问资源。明显如果你肯定某些资源在程序初始化的时候只使用1次、以后不会再改变,就应当使用StaticResource,而程序运行进程中还有可能改变资源应当以DynamicResource情势使用。拿程序的主题来举例,如果程序的皮肤在运行进程中始终不变,以Static情势来使用资源就能够了。如果在程序运行进程中允许用户更改皮肤或配色方案则必须使用DynamicResource来使用资源。
请看下面这个例子,我在Windows资源字典里放置了两个TextBlock类型资源,并分别以StaticResource和DynamicResource方式使用之:
<Window x:Class="WpfApplication10.wnd102"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="wnd102" Height="120" Width="300">
<Window.Resources>
<ResourceDictionary>
<TextBlock x:Key="_txt1" Text="海上生明月"></TextBlock>
<TextBlock x:Key="_txt2" Text="海上生明月"></TextBlock>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button x:Name="_btn1" Content="{StaticResource _txt1}" Height="28" ></Button>
<!--动态资源运行时,才能更新-->
<Button x:Name="_btn2" Content="{DynamicResource _txt2}" Height="28" ></Button>
<Button x:Name="_btn3" Content="Update" Height="28" Click="_btn3_Click" ></Button>
</StackPanel>
</Window>
按钮负责在程序运行进程中对资源词典里面的两个资源进行改变:
private void _btn3_Click(object sender, RoutedEventArgs e)
{
this.Resources["_txt1"] = new TextBlock { Text = "更新成功" };
this.Resources["_txt2"] = new TextBlock { Text = "更新成功" };
}
3. 向程序集中添加2进制资源
常见的利用程序资源有图标、图片、文本、音频、视频等,各种编程语言的编译器或资源编译器都有能力把这些文件编译进目标文件(终究的.exe文件或.dll文件)。资源文件在目标文件里以2进制数据情势存在、构成目标文件的资源段(Resource Section),使用时数据会被提取出来。
为了不把资源词典里的资源和利用程序里面内嵌的资源弄混,我们明确称呼资源词典里面的资源为“WPF资源”或“对象资源”,称呼利用程序内嵌资源为“程序集资源”或“2进制资源”。特别提示1点,WPF中写在<Application.Resource>...</Application.Resource>标签内的资源依然是WPF资源而非2进制资源。
下面让我们看看如何向WPF程序中添加2进制资源并使用它们。
Resources.resx文件内容的组织情势也是“键-值”对,编译后,Resources.resx会构成Properties名称空间中的Resource类,使用这个类的方法或属性就可以获得资源。为了让XAML编译器能够访问这个类,1定要把Resources.resx的访问级别由Internal改成public。利用资源文件编辑器,可以资源文件的字符串里添加两个条目,然后分别在XAML代码和C#代码中访问他们。
在XAML代码中使用Resources.resx中的资源,需要把程序的Properties名称映照为XAML名称空间,然后使用x:Static标签扩大来访问资源。
<Window x:Class="WpfApplication10.wnd103"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prop="clr-namespace:WpfApplication10.Properties"
FontSize="16"
Title="wnd103" Height="130" Width="340">
<StackPanel>
<!--C#中可使用Properties.Resources.访问-->
<TextBlock x:Name="_txtBlock1" Text="{x:Static prop:Resources.password}"></TextBlock>
<TextBlock x:Name="_txtBlock2" Text="{x:Static prop:Resources.userName}"></TextBlock>
</StackPanel>
</Window>
有1点特别提示大家,如果想让外部文件编译进2进制资源,必须在属性窗口把文件的Build Action属性值设为Resource。其实不是每种文件都会自动设置为Resource,比如图片文件会,MP3文件就不会,1般情况下,如果Build Action的值设为Resource,则Copy to Output Directory属性设置为Do Not Copy;如果不希望以资源的情势使用外部文件,可以把Build
Action属性设置为None,而把Copy to Output Directory设置为Copy Always。另外,Build Action属性的下拉列表里面有1个颇具迷惑性的值Embeded Resource,不要选择这个值。
4. 使用PACK URI路径访问2进制资源
WPF对2进制资源的访问有自己的1套方法,称为PACK URI路径。有时候死记硬背能够让读者快速学习又能帮助作者偷点懒。比如,WPF的PACK URI路径,你只需要记住这个格式就能够了:
pack://application,,,[/程序集名称;][可选版本号;][文件夹名称/][文件名称]
而实际上pack://applicationi,,,可以省略、程序集名称和版本号常使用省略值,所以剩下的就只有这个了:
[文件夹名称/][文件名称]
我们看看例子:
<Window x:Class="WpfApplication10.wnd104"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="wnd104" Height="200" Width="300">
<Grid>
<Image x:Name="_image" Source="Resources/Images/Aodi.jpg" Stretch="Fill"></Image>
</Grid>
</Window>
也可以使用C#访问:
_image.Source = new BitmapImage(new Uri(@"Resources/Images/Aodi.jpg", UriKind.Relative));
参考:《深入浅出WPF》
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠