咱们把有用的东西称为资源。“兵马未动,粮草先行”-----程序中的各类数据就是算法的原料和粮草。程序中能够存放数据的地方有不少,能够放在数据库里、能够存储在变量里。介于数据库存储和变量存储之间,咱们还能够把数据存储在程序主体以外的文件里。外部文件与程序主体分离,这就有可能丢失或者损坏,编译器容许咱们把外部文件编译进程序主体、称为程序主体不可分割的一部分。这就是传统意义上的程序资源(也称为二进制资源)。html
WPF不但支持程序级的传统资源,同时还推出了独具特点的对象级资源,每一个界面元素均可以携带本身的资源并可被本身的子级元素共享。好比后面的章节咱们会讲到模板、程序样式和主题就常常放在对象资源里面。这样一来,在WPF程序中数据就分为4个等级存储了:数据库里的数据至关于存放在仓库里面,资源文件里的数据就至关于放进了旅行箱里,WPF对象资源里面的数据至关于存放在携带的背包里,变量里面的数据至关于拿在手里。算法
1.1 WPF对象资源的定义和查找数据库
每一个WPF界面元素都有一个名为Resource的属性,这个属性继承至FrameworkElement类,其类型为ResourceDictionary。ResourceDictionary可以以键值对的形式存储资源,当要使用到某个资源的时候,使用键值对的形式获取资源对象。在保存资源时,ResourceDictionary视资源对象为Object类型,因此再使用资源时先要对资源对象进行类型转换,XAML编译器可以根据Attribute自动识别资源类型,若是类型不对就会抛出异常,但在C#中检索到资源对象以后,类型转换的事情就只能由咱们本身来作了。编程
ResourceDictionary能够存储任意类型的对象。在XAML代码中向Resource添加资源时须要把正确的命名空间引入到XAML代码中,让咱们来看一个例子:app
首先咱们将System命名空间引入XAML代码中并映射为sys名称空间,而后在Windows.Resource里面添加了两个资源条目,一个是string类型,一个是double类型。最后咱们用两个textBlock来消费这两个资源(被注释掉的代码由于数据类型不匹配而抛出异常)。程序运行效果以下图:编程语言
由于在XAML代码里面能够对集合类容及标签扩展进行简写,因此上面代码更常见的书写格式是这样:编辑器
再查找资源时,先查找控件本身的Resource属性,若是没有这个资源程序会沿着逻辑树向上一级进行查找,若是连最顶端容器都没有这个资源,程序就会查找Application.Resource(也就是程序的顶级资源)。若是尚未找到,那么就只能抛出异常了。工具
这就比如每一个界面元素都有本身的一个背包,里面可能装有各类各样的资源,使用的时候打开找一找,若是没有找到还能够去翻看上一层控件的背包,直至找到这个资源或报告没有这个资源为止。学习
若是想在C#代码里面使用XAML代码里面定义的资源,大概格式是这样:ui
或者你明确知道资源放在那个资源字典里,就能够这样检索资源:
你可能会想,若是把资源想CSS或者JS同样放在独立的文件夹里,使用时成套引用、重用时便于分发岂不更好?WPF的资源固然能够作到这一点;ResourceDictionary具备一个名为Source的属性,只要把包含资源定义的文件路径赋值给这个属性就一切搞定了!举个例子,http://wpf.codeplex.com中包含了不少官方/半官方的WPF资源,其中包括WPF工具包和一组很是漂亮的程序皮肤,这些皮肤以资源的形式放在XAML文件中,使用时仅须要将相应的XAML文件添加进项目并使用Source属性进行引用,你的程序就马上变的光鲜照人。
运行效果以下图:
1.2 且“动”且“静”用资源
当资源被存储进资源词典以后,咱们可使用两种方式来使用这些资源-----静态方式和动态方式。Static和Dynamic两个词都是咱们的老朋友了,当这对词同时出现的时候Static指的是程序的非执行状态而Dynamic指的是程序的运行状态。对于资源的使用,Static和Dynamic也是这个意思。静态资源使用StackResource指的是程序载入内存时对资源的一次性使用,以后就不在去访问这个资源了;动态资源(DynamicResource)使用指的是在程序运行过程当中仍然回去访问资源。显然若是你肯定某些资源在程序初始化的时候只使用一次、以后不会再改变,就应该使用StaticResource,而程序运行过程当中还有可能改变资源应该以DynamicResource形式使用。拿程序的主题来举例,若是程序的皮肤在运行过程当中始终不变,以Static形式来使用资源就能够了。若是在程序运行过程当中容许用户更改皮肤或者配色方案则必须使用DynamicResource来使用资源。
请看下面这个例子,我在Windows资源字典里放置了两个TextBlock类型资源,并分别以StaticResource和DynamicResource方式使用之:
界面上的第三个按钮负责在程序运行过程当中对资源词典里面的两个资源进行改变:
实际上,由于第一个按钮是以静态方式使用资源,尽管资源已经更新它也不知道。运行程序,单击第三个按钮,效果以下图:
1.3 向程序集中添加二进制资源
对于资源这个概念,对于WPF初学者会感到迷惑,由于早在WPF出现以前Window应用程序就已经可以携带资源了。Windows应用程序资源的道理和WinZip或WinRAR压缩包的原理差很少,其实是吧一些应用程序必须使用的资源和应用程序自身打包在一块儿,这样资源就不会意外丢死了(反作用就是应用程序体积会变大)。常见的应用程序资源有图标、图片、文本、音频、视频等,各类编程语言的编译器或者资源编译器都有能力把这些文件编译进目标文件(最终的.exe文件或者.dll文件)。资源文件在目标文件里以二进制数据形式存在、造成目标文件的资源段(Resource Section),使用时数据会被提取出来。
为了避免把资源词典里的资源和应用程序里面内嵌的资源搞混,咱们明确称呼资源词典里面的资源为“WPF资源”或“对象资源”,称呼应用程序内嵌资源为“程序集资源”或者“二进制资源”。特别提醒一点,WPF中写在<Application.Resource>...</Application.Resource>标签内的资源仍然是WPF资源而非二进制资源。
下面让咱们看看如何向WPF程序中添加二进制资源并使用它们。
若是要添加的资源是字符串而非文件,咱们可使用应用程序名称空间下的Resources.resx资源文件。打开资源文件的方法是项目管理器中展开Properties文件夹,并双击下面的Resources.resx资源文件。以下图所示:
Resources.resx文件内容的组织形式也是“键-值”对,编译后,Resources.resx会造成Properties名称空间中的Resource类,使用这个类的方法或属性就能获取资源。为了让XAML编译器可以访问这个类,必定要把Resources.resx的访问级别由Internal改成public。利用资源文件编辑器,能够资源文件的字符串里添加两个条目,而后分别在XAML代码和C#代码中访问他们。
在XAML代码中使用Resources.resx中的资源,须要把程序的Properties名称映射为XAML名称空间,而后使用x:Static标签扩展来访问资源。
C#中访问Resources.resx的资源与使用通常的别无二致:
运行效果以下图:
使用Resources.resx最大的好处就是便于程序国际化,本地化。若是你想把界面改成英文版,只须要把资源里的值改成英文就能够了,以下图所示,由于在程序中访问资源使用的是资源的名,因此代码无需改动:
若是要添加的资源不是字符串,而是图标、图片、音频或者视屏。方法就不是使用Resources.resx了,WPF不支持这么作。在WPF使用外部文件做为资源,仅须要将其简单的放入项目便可。方法是在项目管理器上右击项目名称,在弹出的菜单里选择New-->NewFolder,按须要新建几层文件夹来存放资源,而后在恰当的文件夹上右击,在弹出的菜单里选择Add--->Existing Item...,在文件对话框里选择文件后单击Add按钮,文件就以资源的形式加入项目中了。
若是在程序里面添加一个MP3文件和一个图片文件,结果文件的体积会膨胀好几兆。以下图:
有一点特别提醒你们,若是想让外部文件编译进二进制资源,必须在属性窗口把文件的Build Action属性值设为Resource。并非每种文件都会自动设置为Resource,好比图片文件会,MP3文件就不会,通常状况下,若是Build Action的值设为Resource,则Copy to Output Directory属性设置为Do Not Copy;若是不但愿以资源的形式使用外部文件,能够把Build Action属性设置为None,而把Copy to Output Directory设置为Copy Always。另外,Build Action属性的下拉列表里面有一个颇具迷惑性的值Embeded Resource,不要选择这个值。
1.4 使用PACK URI路径访问二进制资源
WPF对二进制资源的访问有本身的一套方法,称为PACK URI路径。有时候死记硬背可以让读者快速学习又能帮助做者偷点懒。好比,WPF的PACK URI路径,你只须要记住这个格式就能够了:
而实际上pack://applicationi,,,能够省略、程序集名称和版本号常使用省略值,因此剩下的就只有这个了:
前面的例子中,咱们向资源中添加了一张名为20090102191236877.gif的图片,它在项目中的路径是Resource/Image/20090102191236877.gif,原封不动,使用这个路径就能够访问到图片了。咱们用这个图片填充一个<Image/>元素并把<image/>元素做为窗体的背景。
或
与之等价的C#代码以下:
或
运行效果以下图所示:
在使用pack uri路径时有如下几点须要注意: