《Programming WPF》翻译 第6章 1.创建和使用资源

时间:2023-03-09 06:00:07
《Programming WPF》翻译 第6章 1.创建和使用资源

原文:《Programming WPF》翻译 第6章 1.创建和使用资源

资源这个词具有非常广泛的意义。任何对象都可以是一个资源。一个在用户界面中经常使用的Brush或者Color可以是一个资源。一段文本或者一个图形也可以是一个资源。没有什么特殊的对象不可以成为一个资源。资源的底层处理机制确保了获取你所需要的资源成为可能,而不闭关心这个资源是什么;同时,这套机制可以简单的识别和定位对象。

资源管理的核心是ResourceDictionary这个类。这是一个相当简单的集合类,就像一个普通的Hashtable,允许以关键字聚合对象,同时提供一个索引器,从而获取到使用了这些关键字的对象。因此,原则上,使用ResourceDictionary就像使用一个Hashtable一样,正如范例6-1所示:

示例6-1

《Programming WPF》翻译 第6章 1.创建和使用资源ResourceDictionary myDictionary = new ResourceDictionary( );

《Programming WPF》翻译 第6章 1.创建和使用资源myDictionary.Add("Foo", "Bar");

《Programming WPF》翻译 第6章 1.创建和使用资源myDictionary.Add("HW", "Hello, world");

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源Console.WriteLine(myDictionary["Foo"]);

《Programming WPF》翻译 第6章 1.创建和使用资源Console.WriteLine(myDictionary["HW"]);

实际上,没有必要如此创建一个ResourceDictionary对象。代替的,你可以正常

使用由WPF提供的一些资源字典。例如,FrameworkElement基类——用户界面的大部分元素都从中派生,对外暴露一个名为Resources的属性,这就是一个资源字典。此外,在Xaml标记中,也可以看到这些资源字典的,正如示例6-1所示:

示例6-2

《Programming WPF》翻译 第6章 1.创建和使用资源<?Mapping XmlNamespace="urn:System" ClrNamespace="System" Assembly="mscorlib" ?>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源<Window x:Class="ResourcePlay.Window1" Text="ResourcePlay"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns:s="urn:System">

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源    <Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源        <SolidColorBrush x:Key="Foo" Color="Green" />

《Programming WPF》翻译 第6章 1.创建和使用资源        <s:String x:Key="HW">Hello, world</s:String>

《Programming WPF》翻译 第6章 1.创建和使用资源    </Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源    <Grid Name="myGrid">

《Programming WPF》翻译 第6章 1.创建和使用资源    </Grid>

《Programming WPF》翻译 第6章 1.创建和使用资源</Window>

x:Key这个属性指定了资源字典中的关键字。原则上,你可以使用任何类型的对象作为关键字,然而实际上,String是最普遍的选择,尽管资源字典中使用的是存储在公有属性中的截然不同的对象实例。



当使用xaml导入资源字典时,WPF可能会选择推迟资源的生成。在特定的环境下,这种做法可以使得xaml资源树的一部分仍然以二进制形式(BAML)存在。只有在需要的时候,才会还原这部分需要的资源。如果在界面出现时并不需要所有的对象,这样做可以明显加快用户界面的启动时间。除了加快速度,这种优化在极大程度上对代码行为并没有直接的效果。尽管如此,如果你的xaml标签出错了,因延迟创建而产生的错误,其浮现的时间可能会超过你的预计。



#译者注:微软推荐XAML被编译成BAML(Binary Application ...二进制语言程序标记语言)。

示例6-3展示了如何获取示例6-2中定义的资源

示例6-3

《Programming WPF》翻译 第6章 1.创建和使用资源Brush b = (Brush) this.Resources["Foo"];

《Programming WPF》翻译 第6章 1.创建和使用资源String s = (String) this.Resources["HW"];

注意到,这段代码使用this.Resources访问ResourceDictionary,这对于在同一个xaml中,由后台代码访问前台中的资源是非常适当的。尽管如此,这种方式并不总是方便。如何让一个xaml文件中的资源可以被应用程序中的所有窗体访问?我们所有窗体中复制同样的资源代码,这是乏味和效率低下的方法。此外,如何获取一个自定义控件的资源,而这个资源是由控件的父窗体指定的;而不是在这个控件中对外暴露这些资源?为了解决这些问题,以及更容易通过用户界面取得一致性,FrameworkElement通过一个有层次的资源范围(resource scope),扩展了ResourceDictionary机制

6.1.1 资源范围

FrameworkElement不光为每个用户界面元素提供了ResourceDictionary,还提供了FindResource方法来获取资源。示例6-4展示了如何使用该方法获取和示例6-4同样的资源。

示例6-4

《Programming WPF》翻译 第6章 1.创建和使用资源Brush b = (Brush) this.FindResource("Foo");

《Programming WPF》翻译 第6章 1.创建和使用资源String s = (String) this.FindResource("HW");

这看起来毫无意思:在示例6-3中,我们已经有this.Resource[“Foo”]这样的方法获取资源,为什么还要有FindResource方法呢?这是因为,如果在指定位置找不到资源,FindResource将继续它的搜索,而不会停止。

示例6-5 使用了示例6-2中myGrid元素,以之取代this,此时,Grid没有任何资源,第一行代码将变量b1设置为null。然而,因为b2是通过FindResource设置的,WPF将考虑一定范围内的所有资源,并不是那些直接设置给Grid的。这个范围是这么确定的:从Grid元素开始,如果没有找到资源,就会检测它的父元素,父元素的父元素。。。一直向上,直至根元素(有可能,父元素恰巧就是根元素——这将是一个很短的搜索。但是通常意义说,将要尽其所能的搜索)。结果,变量b2被设为与示例6-3与中同样的对象。

示例6-5

《Programming WPF》翻译 第6章 1.创建和使用资源// Returns null

《Programming WPF》翻译 第6章 1.创建和使用资源Brush b1 = (Brush) myGrid.Resources["Foo"];

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源// Returns SolidColorBrush from Window.Resources

《Programming WPF》翻译 第6章 1.创建和使用资源Brush b2 = (Brush) myGrid.FindResource("Foo");

到此并未停止。如果FindResource方法直到UI根节点也没有找到指定的资源,这时,将要在application中寻找。不仅所有的framework元素都有一个Resource属性,Application对象也是如此。示例6-6展示了如何在xaml标签中定义应用程序级范围的资源(如果你使用的是Visual Studio 2005的项目模板,你要将这段代码放在MyApp.xaml中)。

示例6-6

《Programming WPF》翻译 第6章 1.创建和使用资源<Application x:Class="ResourcePlay.MyApp"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"

《Programming WPF》翻译 第6章 1.创建和使用资源    StartingUp="AppStartingUp"

《Programming WPF》翻译 第6章 1.创建和使用资源    >

《Programming WPF》翻译 第6章 1.创建和使用资源    <Application.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源        <LinearGradientBrush x:Key="shady" StartPoint="0,0" EndPoint="1,1">

《Programming WPF》翻译 第6章 1.创建和使用资源            <LinearGradientBrush.GradientStops>

《Programming WPF》翻译 第6章 1.创建和使用资源                <GradientStop Offset="0" Color="Red"/>

《Programming WPF》翻译 第6章 1.创建和使用资源                <GradientStop Offset="1" Color="Black"/>

《Programming WPF》翻译 第6章 1.创建和使用资源            </LinearGradientBrush.GradientStops>

《Programming WPF》翻译 第6章 1.创建和使用资源        </LinearGradientBrush>

《Programming WPF》翻译 第6章 1.创建和使用资源    </Application.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源</Application>

应用程序级范围对于程序中的任何对象而言都是很方便的。例如,如果你使用样式和控件模板,肯定要将其放在应用程序的资源中,从而确保应用程序外观上的一致性。

对资源的搜索并未终止到应用程序级别。如果一个资源在UI树上以及应用程序中都不存在,FindResource方法最后将要在系统级范围搜索,这个范围内的设置都是针对系统级而言的,例如被选中项颜色的配置,以及滚动条的宽度。

图6-1展示了一个典型的资源层次。每个应用程序在运行时,都会有一些窗体,而这些窗体内都有一颗由很多元素组成的树。如果FindResource在图中标记为1的元素上被调用,它首先会检索改元素的资源字典。如果没有找到,将会按照途中数字标记的顺序逐层向上搜索,直至达到系统资源这一层。

6-1

《Programming WPF》翻译 第6章 1.创建和使用资源



WPF在系统范围定义了笔刷,字体,以及度量单位;用户也可以在这一级别对其进行配置。这是由SystemColors,SystemFonts以及SystemParameters这些类的静态属性提供的(在这些类中,定义了400以上的资源,这里并未列出,具体语法请参阅SDK文档)。示例6-7从系统范围的资源获取一个Brush对象,并将其设置给toolTipBackgroud对象(参考第7章获取更多Brush的信息)。

示例6-7

《Programming WPF》翻译 第6章 1.创建和使用资源Brush toolTipBackground = (Brush) myGrid.FindResource(SystemColors.InfoBrushKey);

这些系统资源的类使用对象作为资源的关键字,而不是字符串。这样避免了命名冲突的风险,因为一个明确的对象可以唯一的标志系统资源。从而系统资源和自定义资源之间不会有冲突。系统资源的类同时定义了一些静态属性,允许你直接得到相关的对象,而不必从使用FindResource方法。例如,SystemColors类定义了一个InfoBrush属性,可以得到与示例6-7同样的Brush对象,见示例6-8:

示例6-8

《Programming WPF》翻译 第6章 1.创建和使用资源Brush toolTipBackground = SystemColors.InfoBrush;

使用这些属性比通过FindResource方法获取系统资源在编码上要简单的多。尽管如此,使用FindResource方法仍然具有3个优势:

第一个优点,如果用户要改变应用程序的配色方案,而不受限于系统的配色方案,可以通过将这些资源放在应用程序级别,从而覆盖系统级别的设置。示例6-9展示了一个应用程序级别的资源片断,其中重新定义了InfoBrushKey资源的值,这个资源是基于应用程序级别的。

示例6-9

《Programming WPF》翻译 第6章 1.创建和使用资源// (Hypothetical function for retrieving settings)

《Programming WPF》翻译 第6章 1.创建和使用资源Color col = GetColorFromUserSettings( );

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源Application.Current.Resources[SystemColors.InfoBrushKey] = new SolidColorBrush(Colors.Red);

替换过的值只会影响到示例6-7,但不会影响到示例6-8。这是因为后者是直接在系统级别获取资源,而前者,是通过FindResource方法向上搜索,在应用程序级别找到了资源就返回,而不再继续向上搜索了。

第二个优点,通过资源关键字,直接使用在xaml标签中定义的系统资源。

第三个优点,可以使应用程序自动响应系统资源的变更。

后面两个优点使用到了资源引用。

6.1.2 资源引用

目前为止,我们已经看到如何在代码中获取已命名资源的值。既然我们经常使用资源值设置元素属性,我们将着眼于如何为元素属性设置资源值。这看起来想一个可笑的试验步骤。你可能希望代码如同示例6-10:

示例6-10

《Programming WPF》翻译 第6章 1.创建和使用资源this.Background = (Brush) this.FindResource(SystemColors.ControlBrushKey);

我们在逐步接近一个目标:将Background属性设置为一个Brush对象,这个Brush将使用当前控件背景选中的颜色。尽管如此,如果用户在Windows控制面板-显示中改变设置,这个Background属性并不会自动更新。示例6-10有效获取了一个资源值的快照。

示例6-11并未受上述问题所苦。并不是得到一个快照,而是将资源连接到Background属性上。

示例6-11

《Programming WPF》翻译 第6章 1.创建和使用资源this.SetResourceReference(Window.BackgroundProperty, SystemColors.ControlBrushKey);

不同于示例6-10,如果系统资源值有所改变,这个Background属性将会自动获取到新的值。这样的实际结果时,如果用户在Windows控制面板-显示中改变颜色配置,示例6-11将会确保你的用户界面自动更新。

WPF定义了xaml语法,提供了与上述两个示例同样的功能(附录A有关于XAML更多的信息)。可以使用StaticResource和DynamicResource这两个标签。如果使用系统资源或者其他运行时会发生改变的资源,请选则DynamicResource。如果已知资源不会发生改变,选择StaticResource,此时会进行一个快照,从而避免了在连接跟踪资源改变上的性能损失(这些损失虽然很小,但你也要为那些不改变的资源尽量避免)。示例6-12展示了如何同时使用这两个标签。

示例6-12

《Programming WPF》翻译 第6章 1.创建和使用资源<Window x:Class="ResourcePlay.Window1" Text="ResourcePlay"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"

《Programming WPF》翻译 第6章 1.创建和使用资源    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源    <Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源        <SolidColorBrush x:Key="Foo" Color="LightGreen" />

《Programming WPF》翻译 第6章 1.创建和使用资源    </Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源    <Grid Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">

《Programming WPF》翻译 第6章 1.创建和使用资源        <TextBlock FontSize="36" Width="200" Height="200"

《Programming WPF》翻译 第6章 1.创建和使用资源                   Background="{StaticResource Foo}">Hello!</TextBlock>

《Programming WPF》翻译 第6章 1.创建和使用资源    </Grid>

《Programming WPF》翻译 第6章 1.创建和使用资源</Window>

*的Window标签中,定义了一个brush作为一个资源。TextBlock的Backgroud属性使用StaticResource引入了这个资源。这样做与示例6-10很类似:获取一个快照,而且在应用程序运行时不会改变资源。

Grid的Backgroud属性被设置为系统的“控件”颜色(典型的战舰的灰白色,这种颜色经常用于对话框的背景色)。既然这是一种用户可配置的颜色,所以可以在运行期进行改变,于是我们使用DynamicResource,达到了与示例6-10同样的效果。

这里,DynamicResource语法比StaticResource有一点复杂。这是因为我们希望使用的资源是通过SystemColors.ControlBruhKey对象确定其唯一性的,我们可以尝试使用如下语法:

《Programming WPF》翻译 第6章 1.创建和使用资源    <!-- This will not work as intended -->

《Programming WPF》翻译 第6章 1.创建和使用资源    <Grid Background="{DynamicResource SystemColors.ControlBrushKey}">

以上代码看上去是对的,其实并未按照我们的设想执行,而是被解释为一个对资源动态的引用,这个资源是以字符串“SystemColors.ControlBruhKey”命名,这样的资源是不存在的,从而导致背景色没有被设置。为了获取到真正需要的资源(按静态属性而不是按字符串形式),我们必须使用x:Static标签,正如示例6-11中的代码所示。

6.1.3对图形的复用

将图片和图形放到资源中是很有用的。这样做有两个主要原因。一个原因是图形可能非常复杂,将其直接放入xaml中会导致代码难于阅读。通过将其放入资源标签中,所有UI的结构将会更加清晰。另一个原因是支持复用,我们可以在多个地方使用同样的图形。

有很多方法用于表示图片和图形,这将在第7章介绍。所有这些图形都可以作为资源,虽然对一些特定的类型有很多限制。尤其是,如果你使用从FrameworkElement派生的任何元素作为一个资源,只能使用这个引用一次。这种约束的原因是FrameworkElement是用户界面树的基础。一个元素知道它的父元素以及它的子元素,所以这个元素不可能出现在这棵树的多个地方(当你使用资源的时候,只能使用资源对象,而不能使用其copy副本)

所以虽然在资源中放置了一个Ellipse,或者是Canvas画布中的所有图形,你都只能一次这个图形,因为Ellipse和Canvas都是从FrameworkElement派生的。为了减少混乱,将图形放入资源而从xaml的主要标签部分移除,这样做有时是很有用的。既然这样,使用一次的约束就不是一个大的问题了。示例6-13就是使用了名为Shape的Ellipse资源,演示了如何使用这个资源。

示例6-13

《Programming WPF》翻译 第6章 1.创建和使用资源<Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源    <Ellipse x:Key="shape" Fill="Blue" Width="100" Height="80" />

《Programming WPF》翻译 第6章 1.创建和使用资源</Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源<StackPanel>

《Programming WPF》翻译 第6章 1.创建和使用资源    <Button>Foo</Button>

《Programming WPF》翻译 第6章 1.创建和使用资源    <StaticResource ResourceKey="shape" />

《Programming WPF》翻译 第6章 1.创建和使用资源    <Button>Bar</Button>

《Programming WPF》翻译 第6章 1.创建和使用资源</StackPanel>

StaticResource标签元素可以通过替换ResourceKey,在运行期动态修改。该示例的结果如图6-2所示:

6-2

《Programming WPF》翻译 第6章 1.创建和使用资源

一些绘图类,像GeometryDrawing,DrawingGroup,是作为资源存储图形的最好候选者。既然绘图类不是从FrameworkElement派生的,我们可以*的使用这些类的示例在任何地方。如果需要,DrawingGroup可以把任意多的图形图片放到一个单独的资源图形中,从Drawing类派生的各种不同类型都提供了访问所有WPF图形的机制。参见第7章获取更详细信息。

示例6-14展示了如何定义并使用一个图形资源,典型地使用了Drawing,并配合以DrawingBrush。图6-3显示了相应的结果。

示例6-14

《Programming WPF》翻译 第6章 1.创建和使用资源<Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源    <GeometryDrawing x:Key="drawing" Brush="Green">

《Programming WPF》翻译 第6章 1.创建和使用资源        <GeometryDrawing.Geometry>

《Programming WPF》翻译 第6章 1.创建和使用资源            <EllipseGeometry RadiusX="200" RadiusY="10" />

《Programming WPF》翻译 第6章 1.创建和使用资源        </GeometryDrawing.Geometry>

《Programming WPF》翻译 第6章 1.创建和使用资源    </GeometryDrawing>

《Programming WPF》翻译 第6章 1.创建和使用资源</Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源<Rectangle Width="250" Height="50">

《Programming WPF》翻译 第6章 1.创建和使用资源    <Rectangle.Fill>

《Programming WPF》翻译 第6章 1.创建和使用资源        <DrawingBrush Drawing="{StaticResource drawing}" />

《Programming WPF》翻译 第6章 1.创建和使用资源    </Rectangle.Fill>

《Programming WPF》翻译 第6章 1.创建和使用资源</Rectangle>

6-3



《Programming WPF》翻译 第6章 1.创建和使用资源

可选则地,我们可以定义一个DrawingBrush资源,从而将复杂的片断移动到Resource标签内,从而在你使用资源的标签位置,代码变得相当地简单,正如示例6-15所示,执行结果与示例6-14相同(见图6-3),但是使用资源的标签则由五行变成了一行。

示例6-15

《Programming WPF》翻译 第6章 1.创建和使用资源<Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源    <DrawingBrush x:Key="dbrush" Drawing="{StaticResource drawing}" />

《Programming WPF》翻译 第6章 1.创建和使用资源    <GeometryDrawing x:Key="drawing" Brush="Green">

《Programming WPF》翻译 第6章 1.创建和使用资源        <GeometryDrawing.Geometry>

《Programming WPF》翻译 第6章 1.创建和使用资源            <EllipseGeometry RadiusX="200" RadiusY="10" />

《Programming WPF》翻译 第6章 1.创建和使用资源        </GeometryDrawing.Geometry>

《Programming WPF》翻译 第6章 1.创建和使用资源    </GeometryDrawing>

《Programming WPF》翻译 第6章 1.创建和使用资源</Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源<Rectangle Width="250" Height="50" Fill="{StaticResource dbrush}" />

如果你想在同一个图形出现在多个图像中,你可能想降低一下成为资源的级别,同时使用独立的几何对象作为资源。这一点接下来将会在图形中被提及。示例6-16展示了DrawingBrush标签的用法,在其中嵌套了使用了Geometry资源的GeometryDrawing子标签。(这只是另一个椭圆,和图6-3一样,只不过是青色的。)

示例6-16

《Programming WPF》翻译 第6章 1.创建和使用资源<Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源    <EllipseGeometry x:Key="geom" RadiusX="200" RadiusY="30" />

《Programming WPF》翻译 第6章 1.创建和使用资源</Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源<Rectangle Width="250" Height="50">

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源    <Rectangle.Fill>

《Programming WPF》翻译 第6章 1.创建和使用资源        <DrawingBrush>

《Programming WPF》翻译 第6章 1.创建和使用资源            <DrawingBrush.Drawing>

《Programming WPF》翻译 第6章 1.创建和使用资源                <GeometryDrawing Brush="Cyan" Geometry="{StaticResource geom}" />

《Programming WPF》翻译 第6章 1.创建和使用资源            </DrawingBrush.Drawing>

《Programming WPF》翻译 第6章 1.创建和使用资源        </DrawingBrush>

《Programming WPF》翻译 第6章 1.创建和使用资源    </Rectangle.Fill>

《Programming WPF》翻译 第6章 1.创建和使用资源</Rectangle>

在这个特定的例子中,资源的使用可能看上去有点极端。少许成效可能仅仅是从无到有创建了一个新的几何体。尽管如此,一些几何体,例如PathGeometry,可能会变得相当复杂,但是这种类型的复用,会变得更加有意义。

当图形和几何体功能强大而且可复用而且轻量级的时候,就会产生一个缺点。因为它们并不是恰当的框架元素,从而不能利用WPF的系统布局。你可以使用Brush的比例样式(见第7章)按比例缩放这些元素,但是不能使用面板智能地适应元素的布局(见第7章);因为所有的面板都是框架元素。你可能会想,从中选择一种既有使用框架元素特性(如布局)的能力,又有复用资源的能力——ControlTemplate可以符合你的需要。

示例6-17展示了使用ControlTemplate资源的标签。这个例子使用了Ellipse元素多次,有时,我们不能将Ellipse元素成为一个资源。正如你在图6-4中看到的,每个Ellipse都被Grid独立定位并且设置了大小。更多的模板技术见第5章。

示例6-17

《Programming WPF》翻译 第6章 1.创建和使用资源<Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源    <ControlTemplate x:Key="shapeTemplate">

《Programming WPF》翻译 第6章 1.创建和使用资源        <Ellipse Fill="Blue" Margin="3" />

《Programming WPF》翻译 第6章 1.创建和使用资源    </ControlTemplate>

《Programming WPF》翻译 第6章 1.创建和使用资源</Window.Resources>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源<Grid Width="300" Height="150">

《Programming WPF》翻译 第6章 1.创建和使用资源    <Grid.RowDefinitions>

《Programming WPF》翻译 第6章 1.创建和使用资源        <RowDefinition Height="2*" />

《Programming WPF》翻译 第6章 1.创建和使用资源        <RowDefinition Height="*" />

《Programming WPF》翻译 第6章 1.创建和使用资源    </Grid.RowDefinitions>

《Programming WPF》翻译 第6章 1.创建和使用资源    <Grid.ColumnDefinitions>

《Programming WPF》翻译 第6章 1.创建和使用资源        <ColumnDefinition Width="100" />

《Programming WPF》翻译 第6章 1.创建和使用资源        <ColumnDefinition Width="*" />

《Programming WPF》翻译 第6章 1.创建和使用资源    </Grid.ColumnDefinitions>

《Programming WPF》翻译 第6章 1.创建和使用资源

《Programming WPF》翻译 第6章 1.创建和使用资源    <Control Template="{StaticResource shapeTemplate}"

《Programming WPF》翻译 第6章 1.创建和使用资源             Grid.Row="0" Grid.Column="0" />

《Programming WPF》翻译 第6章 1.创建和使用资源    <Control Template="{StaticResource shapeTemplate}"

《Programming WPF》翻译 第6章 1.创建和使用资源             Grid.Row="0" Grid.Column="1" />

《Programming WPF》翻译 第6章 1.创建和使用资源    <Control Template="{StaticResource shapeTemplate}"

《Programming WPF》翻译 第6章 1.创建和使用资源             Grid.Row="1" Grid.Column="0" />

《Programming WPF》翻译 第6章 1.创建和使用资源    <Control Template="{StaticResource shapeTemplate}"

《Programming WPF》翻译 第6章 1.创建和使用资源             Grid.Row="1" Grid.Column="1" />

《Programming WPF》翻译 第6章 1.创建和使用资源</StackPanel>

6-4



《Programming WPF》翻译 第6章 1.创建和使用资源

控件模板提供了一个复用任意标记的方法,但是如果你不在图形中使用基类FrameworkElement,使用更轻量级的DrawingBrush类会更有效。而且如果你要创建大量包含相似图形的绘图,你甚至可以将独立的几何图形全都共享为资源。所有这些绘图机制将要在第7章介绍。