~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
开发工具与关键技术: 资源的定义与查找
作者:邓崇富
撰写时间:2019 年5 月 21 日
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
每个WPF的界面元素都具有一个名为Resources的属性,这个属性继承自FrameworhElement类,器类型为ResourceDictionary。ResourceDictionary能够以“键一值”对的形式存储资源,当需要使用某个资源时,使用“键一值”对可以索引到资源对象。在保存资源时,ResourceDictionary是资源对象为object类型,所以在使用资源时先要对资源对象进行类型转换,XAML编译器能够根据标签的Attribute自动识别资源类型,如果类型不对就会抛出异常,但是在C#代码里检索到资源对象后,类型的转换的事情就只能由我们自己来做了。
ResourceDictionary可以存储任意类型的对象。在XAML代码中向Resources添加资源时需要把正确的名称空间引入到XAML=代码中。
代码如下面的例子:
<Window x:Class="WPF练习.Window6"
<!--两个引用命名间代码-->
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="Window6" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<!--中文字符-->
<sys:String x:Key="str">
衣带渐宽终不悔,为伊消得人憔悴。
</sys:String>
<!--数字字符-->
<sys:Double x:Key="dbl">3.1415926</sys:Double>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBlock Text="{StaticResource str}" Margin="10"/>
<!--<TextBlock Text="{StaticResource dbl}"/>-->
</Grid>
</Window>
首先将System名称空间引入XAML代码并映射为sys名称空间,然后在Window.Resources属性里添加了两个资源条目,一个是string类型实例、一个是double类型实例,最后用两个TextBlock来用这两个资源。
效果如下图:
在检索资源时,先查找控件自己的Resources属性,如果没有这个资源程序会沿着逻辑树向上一级控件查找,如果连最顶层容器都没有这个资源,程序就会去查找Application.Resources(也就是程序的顶级资源),如果还没有找到,就会抛出异常。
当资源被存储进资源词典后,可以通过两种方式来使用这些资源。一种是静态方式(Static),另一种是动态方式(Dynamic)。当这两个词同时出现的时候Static指的是程序非执行状态而Dynamic指的是程序运行状态。对于资源的使用,Static和Dynamic也是同样的意思。静态资源使用(StaticResource)指的是在程序载入内存时对资源的一次性使用,之后就不再去访问这个资源了;动态资源使用(DynamicResource)使用指的是在程序运行过程中仍然去访问资源。显然,如果你确定某些只在程序初始化的时候使用一次、之后不会再改变,就应该使用StaticResource,而程序运行过程中还有可能改变的资源应该以DynamicResource形式使用。
下面的例子中,我在Window的资源词典中放置了两个TextBlock类型资源并分别以StaticResource和DynamicResource方式来使用它。
<Window x:Class="WPF练习.Window6"
<!—此处省略引用的命名空间-->
Title="Window6" Height="450" Width="800">
<Window.Resources>
<TextBlock x:Key="res1" Text="春蚕到死丝方尽"/>
<TextBlock x:Key="res2" Text="蜡炬成灰泪始干"/>
</Window.Resources>
<Grid>
<Button Width="200" Margin="296,95,296,284" Content="{StaticResource res1}"/>
<Button Width="200" Margin="296,140,296,237" Content="{DynamicResource res2}"/>
<Button Width="200" Margin="296,187,296,190" Content="Update" Click="Button_Click"/>
</Grid>
</Window>
界面上的第三个按钮负责在程序运行过程中对资源词典里的两个资源进行改变:
以下是XAML的后台代码:
public partial class Window6 : Window
{
public Window6()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Resources["res1"] = new TextBlock() { Text = "天涯共此时" };
this.Resources["res2"] = new TextBlock() { Text = "天涯共此时" };
}
}
实际上,因为第一个按钮是以静态方式使用资源,所以尽管资源已经被更新它也不会知道。未点击Update按钮时的效果如第一张图,点击后的效果如第二张图: