WPF之资源
WPF不但支持程序级的传统资源,同时还推出了独具特色的对象级资源,每个界面元素都可以携带自己的资源并可被自己的子级元素共享。
WPF对象资源的定义和查找
每个WPF界面元素都有一个名为Resource的属性,其类型为ResourceDictionary(继承至FrameworkElement类)。
ResourceDictionary能够以键值对的形式存储资源,当要使用到某个资源的时候,使用键值对的形式获取资源对象。
在保存资源时,ResourceDictionary视资源对象为Object类型,使用资源时先要对资源对象进行类型转换,XAML编译器能够根据Attribute自动识别资源类型(类型不对就会抛出异常),在C#中需要手动对资源对象进行类型转换。
ResourceDictionary可以存储任意类型的对象,在XAML代码中向Resource添加资源时需要把正确的命名空间引入到XAML代码中,如下所示:
<Window x:Class="WpfApp.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="100" Width="300">
<Window.Resources>
<ResourceDictionary>
<sys:String x:Key="str">沉舟侧畔千帆过,病树前头万木春。</sys:String>
<sys:Double x:Key="db">3.1415926</sys:Double>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<TextBlock Text="{ StaticResource ResourceKey=str}"/>
<!--<TextBlock Text="{StaticResource ResourceKey=db}"/> 类型错误-->
</StackPanel>
</Window>
将System命名空间引入XAML代码中并映射为sys名称空间,然后在Windows.Resource里面添加了两个资源条目,一个是string类型,一个是double类型。
用两个textBlock来消费这两个资源(被注释掉的代码因为数据类型不匹配而抛出异常),程序运行效果如下图:

在XAML代码里面可以对集合类容及标签扩展进行简写,上面代码的常见书写格式如下:
<TextBlock Text="{ StaticResource str}"/>
在查找资源时,先查找控件自己的Resource属性,如果没有这个资源程序会沿着逻辑树向上一级进行查找,如果连最顶端容器都没有这个资源,程序就会查找Application.Resource(也就是程序的顶级资源)。如果还没有找到,那么就只能抛出异常了。
在C#代码里面使用XAML代码里面定义的资源,格式如下:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string text = (string)this.FindResource("str");
textBox.Text = text;
}
明确知道资源放在那个资源字典里,可以这样检索资源:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string text = (string)this.Resources["str"];
textBox.Text = text;
}
WPF的资源可以做到像CSS或者JS一样放在独立的文件夹里,使用时成套引用、重用时便于分发,只要把包含资源定义的文件路径赋值给ResourceDictionary的Source属性即可:
<Window.Resources>
<ResourceDictionary Source="ShinyRed.xaml"/>
</Window.Resources>
动态、静态使用资源
当资源被存储进资源词典之后,可以使用两种方式来使用这些资源-----静态方式和动态方式。
对于资源的使用,Static指的是程序的非执行状态而Dynamic指的是程序的运行状态。
静态资源使用StaticResource指的是程序载入内存时对资源的一次性使用(之后不在访问),动态资源(DynamicResource)使用指的是在程序运行过程中仍然会去访问资源。
在Windows资源字典里放置了两个TextBlock类型资源,并分别以StaticResource和DynamicResource方式使用之:
<Window.Resources>
<ResourceDictionary>
<TextBlock x:Key="res1" Text="海上生明月"/>
<TextBlock x:Key="res2" Text="海上生明月"/>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Margin="5,5,5,0" Content="{StaticResource res1}" />
<Button Margin="5,5,5,0" Content="{DynamicResource res2}"/>
<Button Margin="5,5,5,0" Content="Update" Click="Button_Click"/>
</StackPanel>
界面上的第三个按钮负责在程序运行过程中对资源词典里面的两个资源进行改变:
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Resources["res1"] = new TextBlock() { Text = "天涯共此时" };
this.Resources["res2"] = new TextBlock() { Text = "天涯共此时" };
}
第一个按钮是以静态方式使用资源,尽管资源已经更新它也不知道。
运行程序,单击第三个按钮,效果如下图:

向程序添加二进制资源
常见的应用程序资源有图标、图片、文本、音频、视频等,各种编程语言的编译器或者资源编译器都有能力把这些文件编译进目标文件(最终的.exe文件或者.dll文件)。
资源文件在目标文件里以二进制数据形式存在、形成目标文件的资源段(Resource Section),使用时数据会被提取出来。
为了区分,称呼资源词典里面的资源为“WPF资源”或“对象资源”,称呼应用程序内嵌资源为“程序集资源”或者“二进制资源”。WPF中写在<Application.Resource>...</Application.Resource>标签内的资源仍然是WPF资源而非二进制资源。
字符串资源
如果要添加的资源是字符串而非文件,可以使用应用程序名称空间下的Resources.resx资源文件。打开资源文件的方法是项目管理器中展开Properties文件夹,并双击下面的Resources.resx资源文件。
Resources.resx文件内容的组织形式是“键-值”对,编译后Resources.resx会形成Properties名称空间中的Resource类,使用这个类的方法或属性就能获取资源。
在资源文件的字符串组里添加两个条目,然后分别在XAML代码和C#代码中访问它们。一定要在资源文件编辑器里把Resources.resx的访问级别由Internal改为public,否则运行会报错。
在XAML代码中使用Resources.resx中的资源,需要把程序的Properties名称映射为XAML名称空间,然后使用x:Static标签扩展来访问资源:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prop="clr-namespace:WpfApp.Properties"
Title="MainWindow" Height="130" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="23" />
<RowDefinition Height="4" />
<RowDefinition Height="23" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Static prop:Resources.UserName}"/>
<TextBlock x:Name="textBlockPassword" Grid.Row="2"/>
<TextBox BorderBrush="Black" Grid.Column="2"/>
<TextBox BorderBrush="Black" Grid.Row="2" Grid.Column="2"/>
</Grid>
</Window>
C#中访问Resources.resx的资源如下:
this.textBlockPassword.Text = Properties.Resources.Password;
效果如下:

使用Resources.resx最大的好处就是便于程序国际化,本地化。
非字符串资源
如果要添加的资源不是字符串,而是图标、图片、音频或者视屏,就不能使用Resources.resx了,WPF不支持这么做。在WPF使用外部文件作为资源,仅需要将其简单的放入项目即可。
方法是在项目管理器上右击项目名称,在弹出的菜单里选择“添加”-->“新建文件夹”,按需要新建几层文件夹来存放资源,然后在恰当的文件夹上右击,在弹出的菜单里选择“添加”--->“现有项”,在文件对话框里选择文件后单击“添加”按钮,文件就以资源的形式加入项目中了。
如果想让外部文件编译进二进制资源,必须在属性窗口把文件的“生成操作”属性值设为“Resource”。并不是每种文件都会自动设置为“Resource”,比如图片文件会,MP3文件就不会,一般情况下,如果“生成操作”的值设为“Resource”,则“复制到输出目录”属性设置为“不复制”;如果不希望以资源的形式使用外部文件,可以把“生成操作”属性设置为“无”,而把“复制到输出目录”设置为“始终复制”。另外,“生成操作”属性的下拉列表里面有一个颇具迷惑性的值“嵌入的资源”,不要选择这个值。
使用Pack URI路径访问二进制资源
WPF对二进制资源的访问有自己的一套方法,称为Pack URI路径。WPF的Pack URI路径只需要记住以下格式:
pack://application,,,[/程序集名称;][可选版本号;][文件夹名称/][文件名称]
实际上pack://applicationi,,,可以省略、程序集名称和版本号常使用省略值,剩下的就只有以下内容:
[文件夹名称/][文件名称]
访问Resource/Images/Rafale.gif,用这个图片填充一个<Image/>元素并把<image/>元素作为窗体的背景。
XAML代码如下:
<Image Source="Resource/Images/Rafale.gif" x:Name="ImageBg" Stretch="Fill"/>
<!--或-->
<Image Source="pack://application:,,,/Resource/Images/Rafale.gif" x:Name="ImageBg" Stretch="Fill"/>
等价的C#代码如下:
Uri imgUri = new Uri(@"Resource/Images/Rafale.gif",UriKind.Relative);
//或
//Uri imgUri = new Uri(@"pack://application:,,,/Resource/Images/Rafale.gif", UriKind.Absolute);
this.ImageBg.Source = new BitmapImage(imgUri);
在使用Pack URI路径时有以下几点需要注意:
- Pack URI使用的是从右向左的正斜线(/)表示路径。
- 使用所略写意味着相对路径,C#代码中的UriKind必须为Relative而且代表根目录的/可以省略。
- 使用完整写法时是绝对路径,C#代码中的UriKind必须为Absolute并且代表根目录的/不能省略。
- 使用相对路径可以借助类似DOS的语法进行导航,比如./代表同级目录,../代表父级目录。
WPF之资源的更多相关文章
- WPF之资源字典zz
最近在看wpf相关东西,虽然有过两年的wpf方面的开发经验,但是当时开发的时候,许多东西一知半解,至今都是模模糊糊,框架基本是别人搭建,自己也就照着模板写写,现在许多东西慢慢的理解了,回顾以前的若干记 ...
- WPF 之 资源(Resource)
1.什么叫WPF的资源(Resource)? 资源是保存在可执行文件中的一种不可执行数据.在WPF的资源中,几乎可以包含图像.字符串等所有的任意CLR对象,只要对象有一个默认的构造函数和独立的属性. ...
- WPF 中资源路径的问题
WPF 中资源路径的问题 1. 引用当前工程的资源(注意xxxx.png的build action 应设置为Resource 或Embedded Resource) <ImageBrush Im ...
- WPF样式资源文件简单运用
WPF通过资源来保存一些可以被重复利用的样式,下面的示例展示了简单的资源样式文件的使用: 一.xaml中定义资源及简单的引用 <Window.Resources > <!--wpf窗 ...
- WPF 访问资源中的Storyboard
原文:WPF 访问资源中的Storyboard <UserControl.Resources> <Storyboard x:Key="testStoryboard" ...
- WPF学习资源整理
WPF(WindowsPresentation Foundation)是微软推出的基于Windows Vista的用户界面框架,属于.NET Framework 3.0的一部分.它提供了统一的编程模型 ...
- WPF 调用资源图片
原文:WPF 调用资源图片 最近做的wpf项目中,在开发的时候,把图片放到了bin下面,采用了imagePath =System.IO.Directory.GetCurrentDirectory()+ ...
- WPF - 资源收集
原文:WPF - 资源收集 OpenExpressApp的UI现在是使用WPF,所以熟悉WPF是必须的,以下我将可能用到的一些相关内容随时记录下来,以备查阅.此篇文章将不断更新,感兴趣的可以看看,也欢 ...
- WPF 为资源字典 添加事件响应的后台类
原文:WPF 为资源字典 添加事件响应的后台类 前言,有许多同学在写WPF程序时在资源字典里加入了其它控件,但又想写事件来控制这个控件,但是资源字典没有CS文件,不像窗体XAML还有一个后台的CS文件 ...
- WPF之资源专题
1.一般程序的资源可以分为四个等级: 数据库中的数据相当于放在仓库里 资源文件里的数据相当于放在旅行箱里 WPF对象资源里的数据相当于携带在背包里 变量中的数据相当于拿在手里 2.资源的查找顺序是沿着 ...
随机推荐
- CF1706E Qpwoeirut and Vertices 题解
题目链接:CF 或者 洛谷 官解看上去挺智慧的,来点朴素的解法.我们来当做纯 ds 题去做.首先明确一点,图中若干个点关于最早连通性的这个问题可以考虑 \(MST\),我们有一类东西叫 \(krusk ...
- Delphi原子操作函数介绍
一.Delphi的原子操作函数 在System.SyncObjs单元中,有一个TInterlocked的密封类,其十多个类函数(class function)其实都是调用的System单元的原子操作函 ...
- Delphi中的注释,仅此一篇
在Pascal中,注释括在大括号中或带星号的圆括号中.Delphi 也认可C++ 风格的注释,即把注释放在双斜线后.例如: {this is a comment} (* this is another ...
- Pandas分组聚合
groupby分组操作详解 在数据分析中,经常会遇到这样的情况:根据某一列(或多列)标签把数据划分为不同的组别,然后再对其进行数据分析.比如,某网站对注册用户的性别或者年龄等进行分组,从而研究出网站用 ...
- JS Leetcode 278. 第一个错误的版本 题解分析
壹 ❀ 引 本题来自LeetCode的278. 第一个错误的版本,难度简单,端午节就应该做点容易的题目缓解心情,题目描述如下: 你是产品经理,目前正在带领一个团队开发新的产品.不幸的是,你的产品的最新 ...
- JS leetcode 宝石与石头 题解分析,正则字符组也有妙用
壹 ❀ 引 简单问题简单做,今天的题目来自leetcode771. 宝石与石头,字符串相关的一道题,题目描述如下: 给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头. S 中每个字符代 ...
- NC24623 Tree Decoration
题目链接 题目 题目描述 Farmer John is decorating his Spring Equinox Tree (like a Christmas tree but popular ab ...
- NC16619 [NOIP2008]传球游戏
题目链接 题目 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时 ...
- Mac M1 在PyCharm中安装(支持GPU)TensorFlow 方法
本文介绍在Mac M1的PyCharm中安装TensorFlow与创建工程的方法,在2021的MacBook Pro (M1 Max处理器)验证OK. 安装TensorFlow与创建工程是在Minif ...
- C++ 多线程的错误和如何避免(11)
不要在对时间敏感的上下文中使用 .get() 先看下面的代码, #include "stdafx.h" #include <future> #include <i ...