WPF中的资源

原创 2013年12月04日 10:27:32

我们把有用的东西称为资源。“兵马未动,粮草先行”——程序中的各种数据就是算法的原料和粮草。WPF不但支持程序级的传统资源,同时还推出了独具特色的对象级资源,每个界面元素都可以携带自己的资源并可被自己的子级元素共享。这样一来,WPF程序中的数据就分为四个等级存储:数据库里的数据相当于存放在仓库里,资源文件里的数据相当于放在旅行箱里,WPF对象资源里数据相当于放在随身携带的背包里,变量中的数据相当于拿在手里。

WPF对象级资源的定义与查找

每个WPF的界面元素都具有一个名为Resources的属性,这个属性继承自FrameworkElement类,其类型为ResourceDictionary。ResourceDictionary能够以“键——值”对的形式存储资源,当需要使用某个资源时,使用“键——值”对可以索引到资源对象。在保存资源时,ResourceDictionary视资源对象为Object类型,所以在使用资源时先要对资源对象进行类型转换,XAML编译器能够根据标签的Attribute自动识别资源类型,如果类型不对就会抛出异常,但在C#代码里检索到资源对象后,类型转换的事情就只能由我们自己来做了。

ResourceDictionary可以存储任意类型的对象。在XAML代码中向Resources添加资源时需要把正确的名称空间引入到XAML代码中。

<Window x:Class="Chapter10.Page193.ResourcesDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <sys:String x:Key="str">我是一个资源文件</sys:String>
        <sys:Double x:Key="dbl">3.1415926</sys:Double>
    </Window.Resources>
    <StackPanel>
        <TextBlock Text="{StaticResource ResourceKey=str}"/>
    </StackPanel>
</Window>

首先将System名称空间引入XAML代码并映射为sys名称空间,然后在Window.Resources属性里添加两个资源条目,一个是string类型实例,一个是double类型实例,最后我们用两个TextBlock来消费这些资源。

在检索资源时,先查找控件自己的Resources属性,如果没有这个资源程序会沿着逻辑树向上一级控件查找,如果连最顶层容器都没有这个资源,程序就会去Application.Resources(也就是程序的顶级资源),如果还没有找到,那就只好抛出异常了。这就好比每个界面元素都有自己的一个背包,里面可能装着各种各样的资源,使用的时候打开找一找,如果没有找打还可以去翻开上一层控件的背包,直到找到资源或报告没有这个资源为止。

如果想在C#代码中使用定义在XAML代码里的资源,大概是这样:

            string text = (string)this.FindResource("str");

或者明确的知道资源放在哪的资源词典里,就可以这样检索资源:

            string text1 = (string)this.Resources["str"];

WPF的资源可以像CSS或Javascript那样独立的放在文件中,使用时成套引用、重用。ResourceDictionary具有一个名为Source的属性,只要把包含资源定义的文件路径赋值给这个属性即可。例如:

    <Window.Resources>
        <ResourceDictionary Source="ShinyRed.xaml"/>
    </Window.Resources>

且“静”且“动”用资源

当资源被存储进资源词典后,我们可以通过两种方式来使用这些资源——静态方式和动态方式。Static和Dynamic两个词是我们的老朋友,Static指的是程序的非执行状态而Dynamic指的是程序运行状态。静态资源使用(StaticResource)指的是程序载入内存时对资源的一次性使用,之后就不再去访问这个资源了;动态资源使用(DynamicResource)指的是在程序运行过程中仍然会去访问资源。拿程序的主题来举例,如果程序皮肤的颜色在运行中始终不变,以StaticResource方式来使用资源就可以了;如果程序运行过程中允许用户更改皮肤的配色方案则必须以DynamicResource方式来使用资源。

请看下面的例子。我们在Window资源词典里放置了两个TextBlock类型资源并分别以StaticResource和DynamicResource方式来使用:

<Window x:Class="Chapter10.Page195.DynamicResouceDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <TextBlock x:Key="res1" Text="海上生明月"/>
        <TextBlock x:Key="res2" Text="海上生明月"/>
    </Window.Resources>
    
    <StackPanel>
        <Button Margin="5" Content="{StaticResource res1}"/>
        <Button Margin="5" Content="{DynamicResource res2}"/>
        <Button Margin="5" Content="Update" Click="Button_Click"/>
    </StackPanel>
</Window>

第三个按钮负责在程序运行过程中对资源词典里的两个资源进行改变:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Resources["res1"] = new TextBlock() { Text = "天涯共此时" };
            this.Resources["res2"] = new TextBlock() { Text = "天涯共此时" };

        }

实际上,因为第一个按钮是以静态方式使用资源,所以尽管资源已经被更新它也不会知道。第二个按钮是动态资源的方式,所以当后台代码更新资源时,界面上也会相应的改变。


向程序中添加二进制资源

Windows应用程序资源的道理与Winzip或WinRAR压缩包的道理差不多,实际上是把一些应用程序必须使用的资源与应用程序自身打包在一起,这样资源就不会意外丢失(副作用就是应用程序体积变大)。常见的应用程序资源有图标、图片、文本、视频、音频等,各种编程语言的编译器或资源编译器都有能力把这些文件编译进目标文件(最终的.exe或.dll文件),资源文件在目标文件里是以二进制数据的形式存在,行程目标文件的资源段(Resource Section),使用时数据会被提取出来。

为了不把资源词典里资源和应用程序内嵌的资源搞混,我们明确地称呼资源词典里的资源为“WPF资源”或“对象资源”,程序应用程序的内嵌资源为“程序集资源”或“二进制资源”。

下面我们看看如何向WPF程序添加二进制资源并使用他们。

如果要添加的资源是字符串而非文件,我们可以使用应用程序Properties名称空间中的Resources.resx资源文件。打开资源文件的方法是在项目管理器中展开Properties结点并双击Resources.resx:


Resources.resx文件内容的组织形式也是“键——值”对,编译后,Resources.resx会形成Properties名称空间中的Resources类,使用这个类的方法或属性就能获取资源。为了让XAML编译器能够访问这个类,一定要把Resources.resx的访问级别由Internal改为Public。利用资源文件编辑器,可以在资源文件的字符串组里添加两个条目,然后分别在XAML和C#代码中访问他们。


在XAML代码中使用Resources.resx中的资源,先要把程序的Properties名称空间映射为XAML名称空间,然后使用x:Static标签扩展来访问资源(x:Static在XAML界面里访问cs类里面的静态属性或字段):

<Window x:Class="Chapter10.Page196.ResoucesDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        
        xmlns:prop="clr-namespace:Chapter10.Page196.ResoucesDemo.Properties"
        
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="5">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="4"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="23"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="23"/>
        </Grid.RowDefinitions>
        <TextBlock Text="{x:Static prop:Resources.UserName}"/>
        <TextBlock x:Name="textBlockPassword" Grid.Row="2"/>
        <TextBox BorderBrush="Black" Grid.Column="2"/>
        <TextBox BorderBrush="Black" Grid.Column="2" Grid.Row="2"/>
    </Grid>
</Window>

C#中访问Resources.resx中的资源的使用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Chapter10.Page196.ResoucesDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.textBlockPassword.Text = Properties.Resources.Password;
        }
    }
}

使用Resources.resx最大的好处就是便于程序的国际化、本地化。如果我们想把界面改为英文版,只需要把资源的值改为相应的英文即可。


如果需要添加的资源不是字符串而是图标、图片、音频或视频,方法就不是使用Resources.resx了,WPF不支持这样做。在WPF中使用外部文件作为资源,仅需要简单地将其加入项目即可。方法是在项目是在项目管理器中右击项目名称,在弹出菜单里选择Add——>NewFolder,按需要新建基层文件夹来组织资源,然后在恰当的文件夹上右击,在弹出的菜单里选择Add——>Existing Item,在文件对话框里选择文件后单击Add按钮,文件就以资源的形式加入到项目中。

如果想让外部文件编译进目标成为二进制资源,必须在属性窗口中把文件的BuildAction属性值设为Resource。并不是每种文件都会自动设为Resource,比如图片文件会,MP3文件就不会。一般情况下如果BuildAction属性被设为Resource,则Copy to Output Directory属性就设为Do not copy;如果不希望以资源的形式使用外部文件,可以把Build Action设为None,而把Copy to output Directory设为Copy Always。另外,Build Action属性的下拉列表里有一个颇具迷惑性的值Embedded Resource,不要选择这个值。


使用Pack URI 路径访问二进制资源

前面例子中我们添加另一个名为Bomber.jpg的图片,它在项目里的路径是Image/Bomber.jpg,原封不动的使用这个路径就可以访问这个图片了。

<Image Source="Image/Bomber.jpg" x:Name="img"/>

等同于C#代码为:

            Uri imgUri = new Uri(@"Image/Bomber.jpg", UriKind.Relative);
            img.Source = new BitmapImage(imgUri);

UriKind必须为Relative,代表根目录的/可以省略。Absolute代表根目录的/不能省略。

WPF中的资源(一) - 静态资源和动态资源

WPF中,每个界面元素都含有一个名为Resources的属性,其存储的是以“键-值”对形式存在的资源,而其子级元素在使用这些资源时会从Resources中找到这些资源。在子级元素引用的资源分为Stat...
  • lzhui1987
  • lzhui1987
  • 2016年08月29日 09:28
  • 1794

WPF对象级资源的定义与查找

文章概述: 本演示介绍了如何定义WPF对象级的资源,并通过XAML代码和C#访问和使用对象级资源。 相关下载(代码、屏幕录像):http://pan.baidu.com/s/1hqvJNY8 在线播放...
  • gjysk
  • gjysk
  • 2014年10月20日 05:44
  • 2028

WPF 列表选择,动态调用ResourceDictionary内资源

做WPF项目经常会碰到让客户从列表中选择样式,选定后,动态更改部件的样式。下面以动态更改一个控件的背景图为例子来说说实现的方法。 如果大家有更好的方法,欢迎在评论中提出来。 控件的背景图使...
  • soft2buy
  • soft2buy
  • 2013年12月14日 16:03
  • 9912

WPF资源字典使用

WPF资源字典使用 资源字典出现的初衷就在于可以实现多个项目之间的共享资源,资源字典只是一个简单的XAML文档,该文档除了存储希望使用的资源之外,不做任何其它的事情。   1.  创建资...
  • ccx_john
  • ccx_john
  • 2013年12月03日 11:14
  • 1326

WPF之资源字典

最近在看wpf相关东西,虽然有过两年的wpf方面的开发经验,但是当时开发的时候,许多东西一知半解,至今都是模模糊糊,框架基本是别人搭建,自己也就照着模板写写,现在许多东西慢慢的理解了,回顾以前的若干记...
  • crazyliyang
  • crazyliyang
  • 2013年12月18日 12:48
  • 1692

wpf 项目添加图片资源

wpf设计器能显示图片但运行时不显示或报错的解决方法。
  • anotheryia
  • anotheryia
  • 2017年03月02日 00:16
  • 1925

WPF调用图片路径,或资源图片(WPF编译器、运行期 引用资源)

WPF调用图片路径,或资源图片 http://www.cnblogs.com/sntetwt/p/5402098.html 一、加载本项目的图片 WPF引入了统一资源标识...
  • stableboy
  • stableboy
  • 2017年01月05日 15:38
  • 948

[WPF] 嵌入资源到DLL,并解决PNG图片问题

在WPF有很多种资源文件存储的方式,就图片的存储就麻烦到极点。 最近自己弄一个项目就遇到这样那样的问题,现在把自己的使用方法总结出来给大伙借鉴借鉴! 在我的项目中,我并不想把所有的图片都存放在文件夹下...
  • qiujuer
  • qiujuer
  • 2014年01月06日 16:46
  • 4317

wpf 图片资源引用问题

自学 wpf 经常 会遇到一些奇怪的问题,很多东西要去尝试,才能得到满意的答案    首先看我遇到问题,图片资源引用,如果是在wpf应用程序中,这样写是没有问题的. 如果换在把这个当dll文件 让别人...
  • suntanyong88
  • suntanyong88
  • 2015年01月04日 11:48
  • 9076

WPF 为资源字典 添加事件响应的后台类

前言,有许多同学在写WPF程序时在资源字典里加入了其它控件,但又想p
  • loryrichie
  • loryrichie
  • 2014年06月19日 23:48
  • 3179
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WPF中的资源
举报原因:
原因补充:

(最多只允许输入30个字)