WPF程序设计指南:Resource

注:一下内容及代码基本来自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}
    返回一个SolidBrush类型的对象,而
    {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,那么先出现的资源会被后出现的资源替代。

 

 

 

 

posted on 2010-12-18 16:37  I过T  阅读(5161)  评论(5编辑  收藏  举报

导航