九,WPF资源
- WPF资源的优点
WPF资源系统是一种保管一系列有用对象的简单方法,从而可以更容易地重用这些对象,它主要有以下优点:- 高效,通过资源可以定义一个对象,并在标记中的多个地方重用,这会使代码变的更加精简,并且更加高效。
- 可维护性,通过资源可以使用低级的格式化细节,并将它们移到方便对其进行修改的中央位置。在XAML中创建资源,相当于在代码中创建常量。
- 适应性,一旦特定的信息和应用程序的其它部分相分离,并且放置到资源部分中,就可以动态地修改它。
- 资源集合
每个元素都是有一个Resources属性(它是在FrameworkElement类中定义的),它存储了一个资源字典集合(它是Resource Dictionary类的实例),资源集合可以包含任意类型的对象,并根据字符串编写索引。例如,以下示例显示了如何定义一个画刷资源:<Window.Resources>
<ImageBrush x:Key="TileBrush" TileMode="Tile"Viewport="0 0 32 32" ImageSource="images/happyface.jpg"/>
</Window.Resources>在以上代码中使用了Key特性(以名称空间前缀x:开头,这会将该画刷放置到XAMl名称空间中,而不是WPF名称空间中),该特性指定了在WIndow.Resources.Collection集合中编写画刷索引的名称,当需要检索资源时,只要使用相同的的名称,就可以使用需要的任何内容。可以在资源部分中实例化任何.Net类,只要该类是XAMl友好的,友好的就是指该类有公有的无参构造函数和可写的属性。以下是一个使用该资源的按钮:
<Button Grid.Row="0" Margin="3" Background="{StaticResource TileBrush}"></Button>
<Button Grid.Row="1" Margin="3" Background="{DynamicResource TileBrush}"></Button> - 静态资源和动态资源的区别
静态资源只从资源集合中获取对象一次,而动态资源在每次需要对象时都会重新从资源集合中查找对象,这意味着可以在同一个键下放置一个全新对象,并且动态资源会应用该变化。下面的按钮事件处理程序使用全新的纯色画刷替换了以上定义的图像画刷TileBrush:private void Button_Click(object sender, RoutedEventArgs e)
{
this.Resources["TileBrush"] = new SolidColorBrush(Colors.AliceBlue);
}动态资源会立即应用该变化,而静态资源不知道它的画刷已经在Resources集合中被其它内容替换了,它仍然使用原来的ImageBrush。但通常不需要使用动态资源,因为动态资源的开销比较大,使用静态资源也能够完美的工作,以下是需要使用动态资源的一般原则:
- 资源具有依赖于系统设置的属性(如当前Windows操作系统的颜色或字体)。
- 计划通过编程替换资源对象(如实现几类动态皮肤特性)。
- 非共享资源
通常,当在多个地方使用某种资源时,使用的是同一个对象,这种行为称为共享,然而,也可能希望告诉解析器在每次使用时创建单独的对象实例,为了关闭共享行为,需要使用Shared特性,如下所示,但很少有理由需要使用非共享的资源:<ImageBrush x:Key="TileBrush" x:Shared="False" Viewport="0 0 32 32" ImageSource="images/happyface.jpg" Opacity="0.3"></ImageBrush>
- 通过代码访问资源
控件能够检索资源,而不需要知道定义资源的确切位置,当尝试为Background属性指定画刷时,WPF会在按钮的资源集合中检索名为TileBrush的资源,然后检查包含StackPanel的资源集合,接下来检查窗口。可以使用FrameworkElement.FindResource()方法以相同的方式查找资源, 如:private void Button_Click(object sender, RoutedEventArgs e)
{
ImageBrush brush = (ImageBrush)((Button)sender).FindResource("TileBrush");
}可以使用TryFindResource()方法替代FindResource()方法,如果找不到资源,它会返回一个空引用,而不是抛出一个异常。
- 应用程序资源
窗口不是查找资源的最后一站,如果在控件或容器中找不到指定的资源,WPF会继续检查为应用程序定义的资源集合,在VS中,这些资源定义在App.xaml文件的标记中:<Application x:Uid="Application_1" x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ImageBrush x:Key="TileBrush" TileMode="Tile" ViewportUnits="Absolute" Viewport="0 0 32 32" ImageSource="images/happyface.jpg"/>
</Application.Resources>
</Application>定义应用程序资源就是为了在多个窗口中使用资源,但在创建应用程序资源时,需要考虑复杂性和重用性,添加应用程序资源可以得到好的重用性,但是也会增加复杂性,因为没有明确哪些窗口使用给定的资源,一个正确的指导原则是,如果对象需要被广泛重用(例如,在许多窗口中),可以使用应用程序资源,如果只是在两三个窗口中使用,就可以考虑在每个窗口中定义资源。
- 系统资源
查找资源时应用程序资源还不是最后一站,如果在应用程序中没有找到所需要的资源,元素还会继续查找系统资源。动态资源主要用于辅助应用程序对系统环境设置的变化做出响应,但如何检索系统环境设置并在代码中使用它们?为此需要三个类:SystemColors、SystemFonts和SystemParameters,这些类位于System.Windows名称空间中,其中SystemParameters类包装了大量的设置列表,描述了各种屏幕元素的标准尺寸、键盘、鼠标设置及各种图形效果(如阴影)是否已经打开。这些类通过它们的静态属性提供了它们所有的细节,如:
lb.Foreground = new SolidColorBrush(SystemColors.WindowTextColor);
或者为了提高效率,可以使用现成的画刷属性:
lb.Foreground = SystemColors.WindowTextBrush;
在XAML中可以使用静态标记扩展访问静态的SystemColors.WindowTextBrush来为标签设置前景色:
<Label Foreground="{x:Static SystemColors.WindowTextBrush}">My Test</Label>
上面的示例没有使用资源,当解析窗口并且创建标签时,会根据当前窗口文本颜色的快照创建画册,如果在应用程序运行时改变了Windows颜色,Label控件不会更新它的前景色,具有这种行为的应用程序是不太合理的。为了解决这个问题,需要将Label的Foreground属性设置为包装了系统资源的DynamicResource对象,幸运的是,WPF为所有SystemXXX类都提供了用于返回ResourceKey对象引用的补充属性集,使用这些引用可以从系统资源中提取资源,这些属性与直接返回对象的变通属性同名,后面加上单词Key。如SystemColors.WindowTextBrush的资源键是SystemColors.WindowTextBrushKey。下面的代码显示了如何使用来自SystemXXX类的资源:
<Label Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}">My Test</Label>
- 资源字典
如果希望在多个项目间共享资源,可以创建一个资源字典,它是一个简单的XAML文件,该文档除了存储希望使用的资源外,不做其它任何事情。- 创建资源字典
如下是一个创建资源字典的示例:<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ImageBrush x:Key="TileBrush" TileMode="Tile" ViewportUnits="Absolute" Viewport="0 0 32 32" ImageSource="sadface.jpg"/>
</ResourceDictionary> - 使用资源字典
要使用资源字典,需将其添加到应用程序中某些位置的资源集合中,例如:<Application x:Uid="Application_1" x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionaryTest.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
<ImageBrush x:Key="TileBrush" TileMode="Tile" Viewport="0 0 32 32" ImageSource="images/happyface.jpg"/>
</ResourceDictionary>
</Application.Resources>
</Application>ResourceDictionary.MergedDictionaries集合是一个ResourceDictionary对象的集合,使用它可以把多个资源字典文件进行合并。如果希望添加自己的资源,并合并到资源字典中,只需要在MergedDictionaries部分之前或之后放置资源。
使用资源字典的一个原因是定义一个或多个可以重用的应用程序“皮肤”,可将皮肤应用到控件上,另一个原因是存储需要被本地化的内容(如错误消息字符串)。 在程序集之间共享资源
如果希望在多个应用程序之间共享资源字典,可以复制并分发包含资源字典的XAML文件,但是这样不能对版本进行控制。另一种更好的方法是将资源字典编译到一个单独的类库程序集中,并分发组件。在应用程序中如何提取定义在其它程序集中的资源,一种方法是使用代码创建合适的ResourceDictionary对象,例如,有一个类库程序集ResourceLibrary中有一个名为generic.xaml的资源字典,可以使用下面的代码手动创建该资源字典,且手动从创建的资源字典对象的资源集合中检索所需要的资源:
ResourceDictionary resourceDic = new ResourceDictionary();
resourceDic.Source = new Uri("ResourceLibrary;component/generic.xaml", UriKind.Relative);
btnTest.Background = (Brush)resourceDic["TileBrush"];另一种方法是使用ComponentResourceKey标记扩展,使用它为资源创建键名,来告知WPF在程序集之间共享资源。必须将资源字典放到generic.xaml文件中,并且该文件必须被放到应用程序文件夹中的Themes子文件夹中,在generic.xaml文件夹中的资源被认为是默认主题的一部分,并且它们总是可用的。如果有大量的资源,并希望以合理的方式进行组织,可以创建单独的资源字典文件,但要确保将这些资源字典合并到generic.xaml文件中,从而为共享做好准备。下一步是为存储在ResourceLibrary程序集中希望共享的资源创建键名。当使用ComponentResourceKey时,需要提供两部分信息:类库程序集中类的引用和描述性的资源ID,类引用是WPF允许和其它程序集共享资源的关键部分,当使用资源时,需要提供相同的类引用和资源ID。这个类的外观并不重要,它不需要包含代码,定义该类型的程序集就是ComponentResourceKey将要从中查找资源的程序集,如下示例使用了一个命名为CustomResources的类,它没有包含任何代码:
public class CustomResources {}
现在可以使用这个类和资源ID创建键名了:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ResourceLibrary">
<ImageBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:CustomResources},ResourceId=SadTileBrush}"
TileMode="Tile" ViewportUnits="Absolute" Viewport="0 0 32 32" ImageSource="ResourceLibrary;component/sadface.jpg"/>
</ResourceDictionary>在以上代码中,ImageSource属性使用一个相对URI来明确指示图像是ResourceLibrary组件的一部分。
现在已经创建了资源字典,可以在另一个应用程序中使用它了,首先,需要为类库程序集声明名称空间且指定一个前缀:<Window x:Class="WpfApplication1.ResourcesDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:res="clr-namespace:ResourceLibrary;assembly=ResourceLibrary"
Title="ResourcesDemo" Height="300" Width="300">
<Grid>
<Button Background="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type res:CustomResources},
ResourceId=SadTileBrush}}">Test</Button>
</Grid>
</Window>当使用ComponentResourceKey时,必须使用动态资源,而不能使用静态资源。以上的键名定义太复杂,可以定义一个静态属性,让它返回需要使用的正确的ComponentResourceKey。通常,在组件的类中定义该属性,如下所示:
public class CustomResources
{
public static ComponentResourceKey SadTileBrushKey
{
get { return new ComponentResourceKey(typeof(CustomResources), "SadTileBrush"); }
}
}现在可以使用Static标记扩展访问该属性并应用资源了,而不需要在标记中使用很长的ComponentResourceKey:
<Button Background="{DynamicResource {x:Static res:CustomResources.SadTileBrushKey}}"></Button>
这种方便的快捷方法在本质上和前面的SystemXXX类使用的是相同的技术,例如,当检索SystemColors.WindowTextBrushKey时,所接收的也是正确的资源键对象,唯一的区别是,它是私有SystemRourceKey对象,而不是ComponentResourceKey的一个实例。这两个类都继承自ResourceKey对象。
- 创建资源字典
九,WPF资源的更多相关文章
- WPF基础学习笔记整理 (九) 资源
基础知识: WPF的资源是一种保管一系列有用对象的简单方法,方便于重用. WPF UI元素的Resources属性,都是继承自FrameworkElement列,且其类型为ResourceDictio ...
- [原创]WPF资源Binding自定义集合类。
简单介绍一下Wpf资源字典: 每个WPF界面元素都有一个名为Resource的属性,这个属性继承至FrameworkElement类,其类型为ResourceDictionary.ResourceDi ...
- WPF快速入门系列(6)——WPF资源和样式
一.引言 WPF资源系统可以用来保存一些公有对象和样式,从而实现重用这些对象和样式的作用.而WPF样式是重用元素的格式的重要手段,可以理解样式就如CSS一样,尽管我们可以在每个控件中定义格式,但是如果 ...
- WPF 10天修炼 第七天- WPF资源、样式、控件模板
WPF资源 对象资源 WPF允许在XAML标记的任意位置定义资源.比如在特定的控件.窗口或应用程序级别定义资源,WPF资源系统提供的对象资源有如下好处: 1. 高效:使用对象资源可以在一个地方定义而 ...
- WPF资源
在WPF中.有着两种资源, 一种是组件资源:又被称为程序集资源,以二进制存在编译后的程序集中,通常用于存放图片或其他音频文件. 第二种是对象资源:通常放于xaml中.比如WPF的样式和数据绑定特性. ...
- 在独立的文件里定义WPF资源
一.文章概述 本演示介绍怎样在单独的文件里定义WPF资源.并在须要的地方调用相关资源文件. 相关下载(代码.屏幕录像):http://pan.baidu.com/s/1sjO7StB 在线播放:htt ...
- 避免让WPF资源字典变得杂乱臃肿
原文:避免让WPF资源字典变得杂乱臃肿 避免让WPF资源字典变得杂乱臃肿 周银辉 今天看到项目种的一个XXXResource.xaml文件代码 ...
- WPF 资源(StaticResource 静态资源、DynamicResource 动态资源、添加二进制资源、绑定资源树)
原文:WPF 资源(StaticResource 静态资源.DynamicResource 动态资源.添加二进制资源.绑定资源树) 一.WPF对象级(Window对象)资源的定义与查找 实例一: St ...
- WPF快速入门系列(6)—— WPF资源和样式
一.引言 WPF资源系统可以用来保存一些公有对象和样式,从而实现重用这些对象和样式的作用.而WPF样式是重用元素的格式的重要手段,可以理解样式就如CSS一样,尽管我们可以在每个控件中定义格式,但是如果 ...
随机推荐
- jqcss选择器
$("p").css("background-color","red"); $(this) 当前 HTML 元素$("p" ...
- C#编程实现DNS Client和Server(转)
我们大多数人使用DNS主要是用于域名解析,近期有个特殊的需求:通过DNS协议传递特殊数据.翻遍互联网,最终找到了一个强大的C# DNS工具库 ARSoft.Tools.Net library ,感谢 ...
- github/hexo搭建个人博客几个问题总结
问题一:hexo ERROR Deployer not found: github or hexo ERROR Deployer not found: git npm install hexo-dep ...
- [转]不用安装Oracle Client如何使用PLSQL Developer
本文转自:http://www.cnblogs.com/sleepywang/archive/2009/10/13/1582654.html 1. 下载oracle的客户端程序包(30M) 只需要在O ...
- [未完成]关于GUI Java图形化界
"笔记内容完成,整体未完成" GUI 图形化用户界面 用java做图形化用户界面的程序不多,大多用C++和defy.因为,Java做图形化效率低. 首先你要安装一个虚拟机,C++是 ...
- c++、c实现推箱子小游戏
经过四次的修改和优化,终于将推箱子这个游戏完整的写出来了,今天就像大家分享一下这个游戏的编写. 这个游戏界面的编写总的来说不困难,主要是推动箱子的算法. (1)利用数组和windows api 即可写 ...
- jquery之css()改变字体大小,颜色,背景色
转: <script type="text/javascript"> $(document).ready(function() { $("#f ...
- C# 私人笔记
.ADO.NET 连接数据库的模版 string constr = "data source=127.0.0.1\\mysql2008;database=dbtest;integrated ...
- PHP 和Apache的安装和配置
1. apache官网安装指南: http://jingyan.baidu.com/article/29697b912f6539ab20de3cf8.html 2. 官方安装包下载地址: http:/ ...
- ios开发:OC对象的内存分析
最近要开始准备找实习单位了,做做笔试题,看看各位大神的面试经历,发现自己要学习的东西真的还有很多,虽然也做过几个的项目,但是真正拿过笔试题一看,才发现自己对基础这方面的东西,确实有点忽视了,所以最近开 ...