注:一下内容及代码基本来自Charles Petzold著,蔡学庸译,电子工业出版社出版的《Windows Presentation Foundation 程序设计指南》一书
1. 概述
- 就像为了弥补XML没有循环语句而使用了Style一样,Resource是为了弥补XML没有静态只读字段而设计的。
- 和静态只读字段一样,资源对象在运行时只被建立一次,而且被引用他们的element共享
- 所有资源存储在一个ResourceDictionary类型的对象中, 该对象中每个项目都具有一个key,用来识别该对象
- FrameworkElement、FrameworkContentElement、Appliction都定义了一个名为Resources的property,类型为ResourceDictionary
2. 使用格式
例如在一个StackPanel中,定义Recources:
< StackPanel >
< StackPanel.Resources >
...
</ StackPanel.Resources >
...
</ StackPanel >
而在Resources section内,每个资源定义具有以下格式:
< SomeType x:Key ="mykey" ... >
...
</ SomeType >
在使用的时候,可以用attribute语法或者property element语法,来设定具体的property
3. 使用实例
< StackPanel xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s ="clr-namespace:System;assembly=mscorlib" >
< StackPanel.Resources >
< s:Double x:Key ="fontsizeLarge" >
18.7
</ s:Double >
< s:Double x:Key ="fontsizeSmall" >
14.7
</ s:Double >
</ StackPanel.Resources >
< Button HorizontalAlignment ="Center"
VerticalAlignment ="Center"
Margin ="24" >
< Button.FontSize >
<StaticResource ResourceKey="fontsizeLarge" />
</ Button.FontSize >
Button with large FontSize
</ Button >
< Button HorizontalAlignment ="Center"
VerticalAlignment ="Center"
Margin ="24"
FontSize ="{StaticResource fontsizeSmall}" >
Button with small FontSize
</ Button >
</ StackPanel >
- 代码说明:
1. 第一个Button使用property element语法,获取FrontSize资源,使用一个StaticResource的element和一个ResourceKey的attribute,来表示此项目的key
2. 第二个Button使用attribute语法,FrontSize attribute被设定为一个字符串,将“StaticResource”和Key的名字放在大括号内。
- Resources section总是定义在一个element的最顶端,因为任何资源都必须在文件中被引用之前定义。
4. 具有相同key的Resource
- 在特定的Resources Collection内,key不能重复,但是相同的key可以出现在两个Resource collection内。
- 当一个资源必须被定位时,会先从element所引用的TResources collection开始查找,然后沿着这个树状结构往上找,直到找到key为止。如:
代码< StackPanel xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Orientation ="Horizontal" >
< StackPanel.Resources >
< SolidColorBrush x:Key="brushText" Color ="Blue" />
</ StackPanel.Resources >
< StackPanel >
< StackPanel.Resources >
< SolidColorBrush x:Key="brushText" Color ="Red" />
</ StackPanel.Resources >
< Button HorizontalAlignment ="Center"
VerticalAlignment ="Center"
Margin ="24"
Foreground ="{StaticResource brushText}" >
Button with Red text
</ Button >
</ StackPanel >
< StackPanel >
< Button HorizontalAlignment ="Center"
VerticalAlignment ="Center"
Margin ="24"
Foreground ="{StaticResource brushText}" >
Button with Blue text
</ Button >
</ StackPanel >
</ StackPanel >
代码说明:
第一个Button使用红色字体,第二个使用蓝色字体(父元素的资源)
5. 将一个element或者控件定义为资源
- 可以将一个element或者控件定义为资源,例如:
< Button x:Key ="btn"
FontSize ="24" >
Resource Button
</ Button >
然后使用它:< StaticResource ResourceKey ="btn" />但是只能这样使用一次,因为只有一个Button对象可用。
6. 在C#代码中加入一个resource
stack.Resources.Add( " brushText " , new SolidColorBrush(Colors.Blue));
- Resources的类型是ResourceDictionary,ResourceDictionary定义有一个Add方法,第一个参数是key,第二个参数是object。
- 使用的时候,用FindResource方法来找出特定的key(该方法同样具备找祖先的resource的功能)
7. 使用x:Static读取静态属性或字段
- 如果想要将一个Button的Content property设定为SomeClass类的静态property,名为SomeStaticProp,语法为:
Content="{x:Static SomeClass:SomeStaticProp}"
或者在property element中使用一个x:Static element:
< Button.Content >
< x:Static Member ="SomeClass:SomeStaticProp" />
</ Button.Content >
- 也可以在C#代码中定义静态属性或者字段,然后在XML文件中读取。如有C#代码:
代码using System;
using System.Windows;
using System.Windows.Media;
namespace Petzold.AccessStaticFields
{
public static class Constants
{
// Public static members.
public static readonly FontFamily fntfam =
new FontFamily( " Times New Roman Italic " );
public static double FontSize
{
get { return 72 / 0.75 ; }
}
public static readonly LinearGradientBrush brush =
new LinearGradientBrush(Colors.LightGray, Colors.DarkGray,
new Point( 0 , 0 ), new Point( 1 , 1 ));
}
}在XMAL中读取以上的静态只读属性和字段,注意要引用命名空间
代码< Window xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src ="clr-namespace:Petzold.AccessStaticFields"
x:Class ="Petzold.AccessStaticFields.AccessStaticFields"
Title ="Access Static Fields"
SizeToContent ="WidthAndHeight" >
< TextBlock Background ="{x:Static src:Constants.brush}"
FontSize ="{x:Static src:Constants.FontSize}"
TextAlignment ="Center" >
< TextBlock.FontFamily >
<x:Static Member="src:Constants.fntfam" />
</ TextBlock.FontFamily >
Properties from < LineBreak /> Static Fields
</ TextBlock >
</ Window >
8. 关于使用系统的静态属性
- SystemColors、SystemParameters以及SystemFonts类都具有一大群的property,XMAL文件可以用x:Static读取他们
- 这些静态property都是成对出现的,有一个名为Whatever的property,就有一个名为WhatereverKey的property,所以以"Key"结尾的property都返回一个ResourceKey类型的对象
- 例如
{x:Static SystemColors.ActiveCaptionBrush}{x:Static SystemColors.ActiveCaptionBrushKey}
返回一个ResourceKey类型的对象。因此:
Foreground="{StaticResource {x:Static SystemColors.ActiveCaptionBrushKey}}"等于与:
Foreground="{x:Static SystemColors.ActiveCaptionBrush}"而以下的用法是错误的:
Foreground="{StaticResource SystemColors.ActiveCaptionBrushKey}"
9. 动态资源:DynamicResource
- 如果需要element的前景色随着系统的改变而改变,可以使用以下设置:
Foreground="{DynamicResource {x:Static SystemColors.ActiveCaptionBrushKey}}"
完整的语法是:
< Label ... >
< Label.Foreground >
< DynamicResource >
< DynamicResource.ResourceKey >
< x:Static Member ="SystemColors.ActiveCaptionBrushKey" />
</ DynamicResource.ResourceKey >
</ DynamicResource >
</ Label.Foreground >
</ Label >
- 如果使用StaticResource,key被用来存取对象一次,然后对象会被保留;如果使用DynamicResource,此key会被保留,而对象需要的时候会被取用。
- DynamicResource主要用来存取系统资源,比如系统颜色。但是如果要在element或控件上的资源取得相应的效果,需要用绑定。
10. 在定义静态资源时使用动态资源
当你建立成为资源的画刷的时候,也可以使用系统的颜色:
< StackPanel xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Background ="{DynamicResource
{x:Static SystemColors.InactiveCaptionBrushKey}}" >
< StackPanel.Resources >
<LinearGradientBrush x:Key="dynabrush1"
StartPoint ="0 0" EndPoint ="1 1" >
< LinearGradientBrush.GradientStops >
< GradientStop Offset ="0"
Color ="{DynamicResource
{x:Static SystemColors.ActiveCaptionColorKey}}" />
< GradientStop Offset ="1"
Color ="{DynamicResource
{x:Static SystemColors.InactiveCaptionColorKey}}" />
</LinearGradientBrush.GradientStops >
</LinearGradientBrush >
< SolidColorBrush x:Key="dynabrush2"
Color ="{DynamicResource
{x:Static SystemColors.ActiveCaptionColorKey}}" />
</ StackPanel.Resources >
< Label HorizontalAlignment ="Center"
FontSize ="96"
Content ="Dynamic Resources"
Background ="{StaticResource dynabrush1}"
Foreground ="{StaticResource dynabrush2}" />
</ StackPanel >
代码说明:
1. 当系统颜色发生改变的时候,label的前景色和背景色会跟着发生改变,但是两个作为静态资源的Brush并没有被替代,而只是color发生了改变。
2. 如果将label的Background和Foreground改成DynamicResource,此程序不会响应系统颜色的改变。因为当DynamicResource希望重新建立一个被key所引用的对象,而此画刷对象并没有被重新建立
11. 使用与动态资源相同的key覆盖动态资源
< StackPanel xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Orientation ="Horizontal" >
< StackPanel >
< StackPanel.Resources >
< SolidColorBrush
x:Key ="{x:Static SystemColors.ActiveCaptionBrushKey}"
Color ="Red" />
</ StackPanel.Resources >
< Button HorizontalAlignment ="Center"
VerticalAlignment ="Center"
Margin ="24"
Foreground ="{DynamicResource
{x:Static SystemColors.ActiveCaptionBrushKey}}" >
Button with Red text
</ Button >
</ StackPanel >
< StackPanel >
< Button HorizontalAlignment ="Center"
VerticalAlignment ="Center"
Margin ="24"
Foreground ="{DynamicResource
{x:Static SystemColors.ActiveCaptionBrushKey}}" >
Button with Blue text
</ Button >
</ StackPanel >
</ StackPanel >
代码说明:
1. 第一个Button使用的是已经被覆盖了的资源,前景色为红色
2. 第二个Button使用的是没有被覆盖的动态资源,反应的是系统的颜色
12. 合并资源
如果有一个定义了resource dictionary的XAML文件 :MyResources1.xaml
另外有一个定义了resource dictionary的XAML文件 :MyResources2.xaml
现在有一个工程,想要使用这两个文件所定义的资源,你可以让这两个文件成为此项目的一部分,将“Build Action”设定为“Page”或者“Resource”,并在App.xmal文件中:
< Application xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri ="UseCommonResourcesWindow.xaml" >
< Application.Resources >
< ResourceDictionary >
<ResourceDictionary.MergedDictionaries >
< ResourceDictionary Source="MyResources1.xaml" />
< ResourceDictionary Source="MyResources2.xaml" />
</ResourceDictionary.MergedDictionaries >
</ ResourceDictionary >
</ Application.Resources >
</ Application >
如果这些文件中拥有多个相同的key,那么先出现的资源会被后出现的资源替代。