导图社区 wpf 资源篇
WPF是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0的一部分。本图根据网上各位大咖的经验分享以及自身的一些学习体会整理而成,由于时间仓促,很多地方没有注明出处,所以仅供大家学习参考哦。
编辑于2020-11-06 21:14:51WPF资源的使用
1.WPF不但支持程序级的传统资源,同时还推出了独具特色的对象级资源,每个界面元素都可以携带自己的资源并可被自己的子级元素共享。 比如模板、程序样式和主题就经常放在对象资源里面。 这样一来,在WPF程序中数据就分为4个等级存储了: 1.数据库里的数据相当于存放在仓库里面, 2.资源文件里的数据就相当于放进了旅行箱里, 3.WPF对象资源里面的数据相当于存放在携带的背包里, 4.变量里面的数据相当于拿在手里。
1. 资源字典
1.WPF资源系统可以用来保存一些公有对象和样式,从而实现重用这些对象和样式的作用。 2.WPF资源和WPF样式是相关的,我们经常把样式定义在资源中。 资源字典的意义在于: 1.高效,可以通过资源定义对象,并在标记的多个地方使用,这会精简代码 2.可维护性,通过资源使用低级的格式化细节,如字号,并将它们移到便于修改的中央位置。在XAML中创建资源相当于在代码中创建常亮 3.适应性,一旦某些特定信息与应用程序的其他部分分离开来,并放在资源中,那么可以动态的修改这些信息,如修改皮肤或者语言 总结下使用资源字典的步骤: 1.新建并添加资源 2.绑定资源字典,有代码和xaml两种方式 3.使用字典,有代码和xaml两种方式
资源基础介绍
在WPF中,每一个界面元素都是一个对象,并且都有一个名为Resources的属性,该属性存储了一个资源字典集合。 1.这个属性继承于FrameworkElement类,其类型为ResourceDictionary。 1.1由于元素的属性名是复数形式,所以每一个对象可以拥有多个资源, 由于资源的多样化,获取到的资源的类型为object类型, 所以在获取到资源时,必要时要进行转化成符合自己要求的类型; 1.2由其类型可以知对象资源是以键值对的形式来存储的,当需要某个资源时,可以通过key索引来获取。 1.3尽管每个元素都提供了Resources属性,但通常在窗口级别上定义资源,就如上面XAML代码所示的那样。 因为每个元素都可以访问它自己的资源集合中的资源,也可以访问所有父元素的资源集合中的资源。 1.3.1检索资源的顺序 比如下面的例子, 1.3.1.1Textblock会先看一下自身有没有资源的Key为str的, 1.3.1.2如果没有发现的话,会继续沿着逻辑树往上找(也就是Window上找)。直到发现为止, 1.3.1.3如果在XAML中没有找到的话,程序还会在Application.Resources中找找看, 1.3.1.4如果再没有的话,那么就说我找不到(抛出异常) 1.4尽管可以在代码中创建和操作资源,但是通常都是以XAML标签的形式定义资源的。 下面具体看看如何去定义一个资源,具体的XAML代码如下所示: 
代码
<Window x:Class="Chapter_08.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> <ResourceDictionary> <sys:String x:Key="str"> 我是资源 </sys:String> </ResourceDictionary> </Window.Resources> <Grid x:Name="grid"> <TextBlock x:Name="textblock" Text="{StaticResource ResourceKey=str}"/> </Grid> </Window> 在上面代码中资源为属性元素,所以<ResourceDictionary>是可以省略掉的 下面是在后台的等效代码: this.Resources["str1"] = "我是资源"; this.textblock.Text = this.FindResource("str1") as string;
资源字典分类
从资源引用方式分
为了使用XAML标记中的资源,需要一种引用资源的方法,可以通过两个标记来进行引用资源: 静态引用资源:<Button Background="{StaticResource RedBrush}"/> 动态引用资源:<Button Background="{DynamicResource RedBrush}"/> 对于静态资源在第一次创建窗口时,一次性地设置完毕; 而对于动态资源,如果资源发生了改变,应用了该资源的元素会会重新应用资源。 <Window x:Class="ResourceDemo.DynamicResource" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DynamicResource" Height="300" Width="300"> <Window.Resources> <SolidColorBrush x:Key="RedBrush" Color="Red"></SolidColorBrush> </Window.Resources> <StackPanel Margin="5"> <Button Background="{StaticResource RedBrush}" Margin="5" FontSize="14" Content="Use a Static Resource"/> <Button Background="{DynamicResource RedBrush}" Margin="5" FontSize="14" Content="Use a Dynamic Resource"/> <Button Margin="5" FontSize="14" Content="Change the RedBrush to Yellow" Click="ChangeBrushToYellow_Click"/> </StackPanel> </Window> 对应改变资源按钮的后台代码如下所示: private void ChangeBrushToYellow_Click(object sender, RoutedEventArgs e) { // 改变资源 this.Resources["RedBrush"] = new SolidColorBrush(Colors.Yellow); }
StaticResource(静态资源)
Windows8应用中,XAML资源仅支持StaticResource(静态资源) <Button Background="{StaticResource RedBrush}"/> 对应改变资源按钮的后台代码如下所示: private void ChangeBrushToYellow_Click(object sender, RoutedEventArgs e) { // 改变资源 this.Resources["RedBrush"] = new SolidColorBrush(Colors.Yellow); }
DynamicResource(动态资源)
<Button Background="{DynamicResource RedBrush}"/>
从资源应用域分
FrameworkElement.Resources(页面资源字典)
Application.Resources(贯穿整个应用级别的资源)
资源字典文件的创建
如果希望在多个项目之间共享资源的话,就可以创建一个资源字典。 资源字典是一个简单的XAML文档,该文档就是用于存储资源的 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="blueBrush" Color="Blue"/> <FontWeight x:Key="fontWeight">Bold</FontWeight> </ResourceDictionary>
合并多个外部资源字典成为本地字典
1.为了使用资源字典,需要将其合并到应用程序中资源集合位置. 1.1当然你也可以合并到窗口资源集合中. 1.2但是通常是合并到应用程序资源集合中,因为资源字典的目的就是在于多个窗体中共享. 2.具体的XAML代码如下所示:(此例是定义在了app.xaml文件中 <Application x:Class="ResourceDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="DynamicResource.xaml"> <Application.Resources> <!--合并资源字典到Application.Resources中--> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Generic.xaml"/> <!--合并themes文件夹下的资源字典到--> <ResourceDictionary Source="Themes/ShinyRed.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
资源字典的使用
<Window x:Class="ResourceDemo.ResourceUse" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="REsource" Height="100" Width="350" xmlns:sys="clr-namespace:System;assembly=mscorlib"> <Window.Resources> <!--新定义的1个字符串资源--> <sys:String x:Key="nameStr"> LearningHard博客:http://www.cnblogs.com/zhili/ </sys:String> </Window.Resources> <StackPanel> <!--使用资源字典中定义的资源,它定义在app.xaml中,系统会自动去这个文件中寻找相应的资源--> <Button Margin="10" Background="{StaticResource blueBrush}" Content="Blue Button" FontWeight="{StaticResource fontWeight}"/> <!--通过资源key来对资源进行使用--> <TextBlock Text="{StaticResource nameStr}" Margin="10"/> </StackPanel> </Window>
多应用程序共享资源字典
在多个应用程序共享资源怎么办呢? 1.最简单的方法就是在每个应用程序中拷贝一份资源字典的XAML文件,但是这样不能对版本进行控制,显然这不是一个好的办法。 2.更好的办法是将资源字典编译到一个单独的类库程序集中,应用程序可以通过引用程序集的方式来共享资源。这样就达到了在多个应用程序中共享资源的目的。 使用这种方式面临着另一个问题,即如何获得所需要的资源并在应用程序中使用资源。 对此,可以采用两种方法。 1.第一种办法是通过代码创建一个ResourceDictionary对象,再通过指定其Source属性来定位程序中资源字典文件,一旦创建了ResourceDictionary对象,就可以通过key来检索对应的资源,具体的实现代码如下:
通过代码创建一个ResourceDictionary对象
public static void loadRd() { var brushes_rd = new ResourceDictionary();//定义一个资源字典 brushes_rd.Source = new Uri("pack://Application:,,,/testXml;component/dictionary.xaml");//为资源字典的source赋值 Application.Current.Resources = new ResourceDictionary();//将定义好的字典绑定到系统中,此处绑定至app的recources Application.Current.Resources.MergedDictionaries =brushes_rd; } 运用6.0语法糖 public static void loadRd() { var brushes_rd = new ResourceDictionary() { Source = new Uri("pack://Application:,,,/testXml;component/dictionary.xaml") }; Application.Current.Resources = new ResourceDictionary() { MergedDictionaries = { brushes_rd } }; } 直接绑定到当前实例上 this.Resources= new ResourceDictionary() { Source = new Uri("pack://Application:,,,/testXml;component/dictionary.xaml") }; 或 ResourceDictionary resourceDic = new ResourceDictionary(); // ReusableDictionary.xaml是资源字典文件 resourceDic.Source = new Uri("ResourceLibrary;component/ReusableDictionary.xaml", UriKind.Relative); cs中使用: SolidColorBrush blueBrush =(SolidColorBrush)resourceDic["BlueBrush"];
使用ComponentResourceKey标记
2. 向程序添加二进制资源
1.二进制资源 1.1.和对象级资源一样,二进制资源也是对象,但是其所在的位置不是在窗体上,一般在项目下的文件夹或者属性文件件下面。 1.2.除此之外,因为控件查找资源时,会沿着逻辑树查找,如果在树上找不到资源,最后还会在Application.Resources里面找. 1.3.所以越是靠上面的资源,能利用资源的元素越多。(可以理解为站的越高,越容易被更多的元素看到,因为元素都是往上看的)。 1.4. 很多时候,都有程序用到外部的文件. 为了防止操作不当,使文件与程序分离,破坏了程序的完整性, 所以让文件编译到目标文件中(.exe、.dll文件)以二进制的数据存在, 这就是要记录的二进制资源。 1.4.1如果要添加的资源是字符串而不是文件,那么可以使用应用程序Properties名称空间中的Resources.resx资源文件, 1.4.2如果是XAML要访问该资源的话,要把访问修饰符改为Public。如图  2.资源的调用 2.1在后台代码调用资源: Properties.Resources.Password 2.2在XAML中调用形式: xmlns:prop="clr-namespace:Chapter_08.Properties" Text="{x:Static prop:Resources.Password}" 如果需要改为中文的话,可以直接去资源里面修改。该类资源便于国际化、本地化。
1、Resources.resx 文件添加 字符串二进制资源
1.双击 Resources.resx 文件 2.要修改"访问修饰符"为"public" 3.在按照需要点击"字符串"或"添加资源"  程序中引用 代码: <Window x:Class="WpfApplication.Window13" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prop="clr-namespace:WpfApplication.Properties" Title="Window13" Height="300" Width="300"> <!--将二进制资源Properties引入文件,并命名其命名空间为prop--> <Grid> <!--使用prop下的resources二进制资源--> <TextBox Text="{x:Static prop:Resources.UserName}"/> </Grid> </Window>
2、Resources.resx 文件添加 图片二进制资源
除此之外还有一类就是文件型二进制资源。把文件编译成二进制文件, 下面说一下具体的做法, 1.在项目中添加一个文件夹Resources(可以是其他的名字)然后添加现有项,  2.然后设置资源的属性的生成操作选项为:Resource,且复制到目录选项为:不复制, (如果不希望以资源的形式使用外部文件,那么生成操作选项为:None,复制到目录选择 :始终复制。)  引用资源 一种引用资源是在XAML中引用 <Image Name="img" Source="Resources/Images/4.jpg" Stretch="Fill"/> 另一中引用时在cs后台代码中引用,其中有绝对路径和相对路径之分,下面列出两种形式: img.Source = new BitmapImage(new Uri(@"Resources/Images/4.jpg", UriKind.Relative)); //Uri imgUri1 = new Uri(@"Resources/Images/4.jpg", UriKind.Relative); Uri imgUri1 = new Uri(@"pack://application:,,,/Resources/Images/4.jpg", UriKind.Absolute); this.image.Source = new BitmapImage(imgUri1); 其中相对路径直接写程序下面的文件夹到文件的路径, 绝对路径格式为pack://application,,,:[/程序集名][/可选版本号][/文件夹名]/文件名称。 当然,随着资源被编译成二进制文件,所以生成的exe文件也变大了。
3. 资源绑定树(XmlDataProvider:XML 数据)
效果:  TreeFile.xaml: XPath="FileSystem/Folder" 生成数据集合的 XPath 查询 <ResourceDictionary 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" > <XmlDataProvider x:Key="xdp" XPath="FileSystem/Folder"> <x:XData> <FileSystem xmlns=""> <Folder Name="基础设置"> <Folder Name="数据库地址" Value="Pages/Page_SqlAddress.xaml"/> <Folder Name="配置一次图" Value="Pages/Page_ConfigControls.xaml"/> </Folder> <Folder Name="终端模板管理"> <Folder Name="终端管理" Value="Pages/Page_Products.xaml"/> <Folder Name="终端变量管理" Value="Pages/Page_Varibles.xaml"/> </Folder> <Folder Name="配置生成"> <Folder Name="生成全部" Value="Pages/Page_BuildAll.xaml"/> <Folder Name="单步生成-终端" Value="Pages/Page_BuildProducts.xaml"/> <Folder Name="单步生成-终端变量" Value="Pages/Page_BuildVaribles.xaml"/> <Folder Name="单步生成-设备" Value="Pages/Page_BuildEquipment.xaml"/> <Folder Name="单步生成-一次图" Value="Pages/Page_BuildGraphical.xaml"/> </Folder> </FileSystem> </x:XData> </XmlDataProvider> <ResourceDictionary> App.xaml <Application x:Class="AutomaticConfigurationAPP.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" > <!--启始页等一堆参数设置,相当于控制台程序Main,是整个程序入口--> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/Resources/Xml/TreeFile.xaml" /> <ResourceDictionary Source="pack://application:,,,/AutomaticConfigurationAPP;component/Styles/Bootstrap.xaml"/> <ResourceDictionary Source="pack://application:,,,/AutomaticConfigurationAPP;component/PathGeometries/Glyphicons.xaml"/> <!--<ResourceDictionary Source="/Themes/Theme.xaml" />--> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application> View层 <Window x:Class="AutomaticConfigurationAPP.MWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="配置文件自动生成工具" Height="500" Width="800" Icon="/AutomaticConfigurationAPP;component/bitbug_favicon%20%282%29.ico"> <Window.Background> <ImageBrush ImageSource="/AutomaticConfigurationAPP;component/Images/background_blue.jpg" Stretch="Fill" TileMode="Tile" Viewport="0,0,1174,600" ViewportUnits="Absolute" /> </Window.Background> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="160"/> <ColumnDefinition Width="2"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="8"/> </Grid.RowDefinitions> <TreeView ItemsSource="{Binding Source={StaticResource xdp}}" Grid.Row="0" Grid.Column="0" x:Name="TreeRoot" Background="#E5EBF3"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding XPath=Folder}"> <TextBlock x:Name="a" Text="{Binding XPath=@Name}" FontSize="12"/> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> <Frame x:Name="PageContext" Grid.Row="0" Grid.Column="2" Background="#F3F3F3" BorderBrush="#888" BorderThickness="1" NavigationUIVisibility="Visible" Source="{Binding ElementName=TreeRoot, Path=SelectedItem.Attributes[Value].Value}"/> </Grid> </Window>
4. WPF中资源引用方式汇总
在WPF应用程序开发中,总是难以记住各种访问资源的方法,遂逐一记下。
程序集资源
1.资源在编译的时候嵌入到程序集中。 WPF中的XAML会被编译为BAML, 图片等其他资源均被编译到程序集中AssemblyResources.g.resources中  1.1为了能够成功使用程序集资源,需要注意一下两点: 1.1.1资源的Build Action必须是Resource,不复制到输出目录。 1.1.2不要在Project Properties中使用Resource选项卡,WPF不支持这种类型的资源URI。 2.使用资源 2.1可以在XAML中使用如下方式使用资源 <Image Source="Image/yun.png"></Image> 2.2也可以使用代码,不过这里有相对路径和绝对路径之分 2.2.1 img.Source=new BitmapImage(new Uri(@"E:\Photo\Image\yun.png")); 2.2.2 img.Source=new BitmapImage(new Uri("Image/yun.png",UriKind.Relative)); 3.但在实际项目中,资源总在另外一个程序集中,那么就需要跨程序集访问资源。 语法如下: pack://application:,,,/AssemblyName;Component/ResourceName 3.1首先要引用具有资源的程序集 3.1.1 在XAML中如下使用 <Grid> <Grid.Background> <ImageBrush ImageSource="pack://application:,,,/Controls;Component/Image/yun.png"></ImageBrush> </Grid.Background> </Grid> 3.1.2在代码中也是同样的使用方式 img.Source=new BitmapImage(new Uri("pack://application:,,,/Controls;Component/Image/yun.png")); 4.另外就是资源字典的使用, 一个资源字典中可以包含程序中需要使用的样式,画笔等等,资源文件也可再包含资源文件 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Dictionary.xaml"></ResourceDictionary> <ResourceDictionary Source="Dictionary2.xaml"></ResourceDictionary> </ResourceDictionary.MergedDictionaries> <Style x:Key="btnStyle" TargetType="Button"> <Setter Property="Background"> <Setter.Value> <ImageBrush ImageSource="Image/yun.png"></ImageBrush> </Setter.Value> </Setter> </Style> </ResourceDictionary> 5.如果程序需要使用到换肤功能的话,那么最好由Application来加载统一的资源字典,这样实现换肤功能的话,其实就是将Application下的这一套资源换成另一套,唯一的弊端就是,在vs中看不到已经使用的样式,只有运行起来才能看到。控件换肤也是同样的道理。可以看下下面的例子 http://files.cnblogs.com/action98/WPF_ChangeSkin_Sample.rar http://files.cnblogs.com/action98/CustomControl%E6%8E%A7%E4%BB%B6%E6%8D%A2%E8%82%A4.rar
内容文件
二.内容文件 1.在如下情况中不宜使用程序集资源,而是使用应用程序部署文件。 1.1希望改变资源文件,而又不想重新编译应用程序。 1.2资源文件非常大。 1.3资源文件是可选的,并且可以不随程序集一起部署。 1.4资源是声音文件。 2.为了能够成功使用内容文件,需要注意两点 2.1将资源的Build Action始终设置为Content 2.2将资源的Copy to Output Directory始终设置为CopyAlways 2.3使用的时候同程序集使用的是同一套URI方法