WPF(资源调用)
资源初步认识https://blog.csdn.net/breakbridge/article/details/116271634
一、资源键
大多少时候我们定义一个资源都是将其Key设置为一个字符串,但有时候我们也可以将Key设置为 ComponentResourceKey 对象。
<Application x:Class="WpfAppResource1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="appSolid1" Color="Green" />
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="#666" />
</ResourceDictionary>
</Application.Resources>
</Application>
二、获取资源
这里只讲诉全局的资源,元素的资源同理。
1.Application.Current
- 获取字符串作为Key的资源:
//获取资源
var rs2 = Application.Current.Resources["appSolid1"];
- 获取ComponentResourceKey作为Key的资源:
ComponentResourceKey resourceKey = new ComponentResourceKey(typeof(MainWindow), "coldWaterBrush");
//获取资源
var rs1 = Application.Current.Resources[resourceKey];
2.FrameworkElement.FindResource
- 获取字符串作为Key的资源:
//获取资源
var rs3 = this.FindResource("appSolid1");
- 获取ComponentResourceKey作为Key的资源:
ComponentResourceKey resourceKey = new ComponentResourceKey(typeof(MainWindow), "coldWaterBrush");
//获取资源
var rs3 = this.FindResource(resourceKey);
PS:这里不能用 this.Resources["appSolid1"]; 这只能获取该元素自身的资源
三、修改资源
修改资源自能对对应的资源字典赋值,不能是修改资源的值。
var rs2 = Application.Current.Resources["appSolid1"];
//rs2 = new LinearGradientBrush(Colors.Red, Colors.Green, 45.0); //无效
//(rs2 as SolidColorBrush).Color = Colors.Red; //会提示异常
Application.Current.Resources["appSolid1"] = new LinearGradientBrush(Colors.Red, Colors.Green, 45.0);
直接对rs2赋值是无效的,
四、同Key资源
当存在两个Key相同的资源时,会应用哪一个呢?
1.Dictionary.xaml 与 App.xaml
在同一个资源文件里有两个同样Key的资源会提示异常,当同样Key的资源在两个文件里面时是不会出现异常的。
<!-- Dictionary1.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1">
<SolidColorBrush x:Key="appSolid1" Color="Red" />
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="#FF5FA7FD" />
</ResourceDictionary>
<!-- App.xaml -->
<Application x:Class="WpfAppResource1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfAppResource1;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="appSolid1" Color="Green" />
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="#666" />
</ResourceDictionary>
</Application.Resources>
</Application>
当应用Key为appSolid1的资源时,是显示Green还是Red呢?
测试可知,会显示Green,这表示优先应用非资源字典里面的样式。 (不是因为Green样式在Red样式后面,放在前面也是一样)
2.Dictionary.xaml 与 Dictionary.xaml
若是将其放在另一个资源文件里面时:
<!-- Dictionary2.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1">
<SolidColorBrush x:Key="appSolid1" Color="Green" />
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="#666" />
</ResourceDictionary>
<!-- App.xaml -->
<Application x:Class="WpfAppResource1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfAppResource1;component/Dictionary2.xaml"/>
<ResourceDictionary Source="/WpfAppResource1;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
同名的会应用最后定义的资源文件,这里就会应用Dictionary1中的样式。 若是在Dictionary2中调用appSolid1样式时,也是调用的Dictionary1中的appSolid1样式。
3.App.xaml 与 Themes.Generic.xaml
当在App.xaml 和 generic.xaml 中应用了同样的样式,会优先应用App.xaml中的
PS: generic.xaml 中的样式不能通过上述的方法获取和修改资源。
五、两个Key的区别
假设有两个资源字典:
<!-- Dictionary1.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1">
<SolidColorBrush x:Key="appSolid1" Color="Red" />
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="Blue" />
</ResourceDictionary>
<!-- Dictionary2.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1">
<Style TargetType="Button">
<Setter Property="FontSize" Value="20"/>
<Setter Property="Background" Value="{StaticResource appSolid1}"/>
<Setter Property="Foreground" Value="{StaticResource {ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}}"/>
</Style>
</ResourceDictionary>
<!-- App.xaml -->
<Application x:Class="WpfAppResource1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfAppResource1;component/Dictionary2.xaml"/>
<ResourceDictionary Source="/WpfAppResource1;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
这里应用的是StaticResource,若是 DynamicResource这里看不出区别。因为应用的是StaticResource,若是key都是字符串类型时,需先定义Dictionary1。若是我们先定义Dictionary2会怎样呢???
应用字符串作为Key的资源会提示找不到,而ComponentResourceKey的资源是可以应用的。
六、访问其他程序集中的资源
1.资源字典
现有程序集 WpfAppResource1,其中有资源 Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1">
<SolidColorBrush x:Key="appSolid1" Color="Red" />
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="Blue" />
</ResourceDictionary>
当我们需在 WpfAppResource2 中访问 WpfAppResource1 中的 Dictionary1.xaml 时,只需引用该资源即可:
<Application x:Class="WpfAppResource2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource2"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/WpfAppResource1;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
PS:当 WpfAppResource2 作为主窗体启动时, WpfAppResource1 的 App.xaml 是无效的,即在该文件中定义的所有样式都不起作用。
2. Generic.xaml
当我们自定义控件时,静态构造函数中调用DefaultStyleKeyProperty.OverrideMetadata()方法时,就会在Generic.xaml中获取默认样式。
当我们在WpfAppResource1自定义一个控件,如下:
namespace WpfAppResource1
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
public class Btn : Button
{
static Btn()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Btn), new FrameworkPropertyMetadata(typeof(Btn)));
}
}
}
<!-- Generic.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppResource1">
<Style TargetType="local:Btn">
<Setter Property="FontSize" Value="20" />
<Setter Property="Background" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="20">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
这时我们就可以在 WpfAppResource2 中访问Btn了。若是我们在 WpfAppResource2 的Generic.xaml中也定义一个上述一样的Btn的样式,这是无效的,就算 WpfAppResource1中没有定义Btn的样式也不行,所以在哪创建了自定义控件就只能在哪个程序集的Generic中定义默认样式。
这里再次说明一下两个Key的区别:
当WpfAppResource1的Generic.xaml如下时,我们可以在WpfAppResource2中直接访问ComponentResourceKey 定义的样式,而用字符串作为key就不行。
<!-- Generic.xaml --> <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfAppResource1"> <SolidColorBrush x:Key="appSolid1" Color="Red" /> <SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MainWindow}, ResourceId=coldWaterBrush}" Color="Blue" /> </ResourceDictionary>
七、XML名称空间
using System.Windows.Markup;
[assembly: XmlnsDefinition("http://schemas.bridge.com/WpfAppResource1/", "WpfAppResource1")]
[assembly: XmlnsPrefix("http://schemas.bridge.com/WpfAppResource1/", "custom")]
namespace WpfAppResource1
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
public class Btn : Button
{
static Btn()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Btn), new FrameworkPropertyMetadata(typeof(Btn)));
}
}
}
- XmlnsDefinition:指定 XAML 命名空间与 CLR 命名空间之间按程序集进行的映射,然后 XAML 对象编写器或 XAML 架构上下文使用后一种命名空间进行类型解析。
- XmlnsPrefix:当在 XAML 文件(序列化)中编写元素和特性时,或与具有 XAML 编辑功能的设计环境进行交互时,标识要与 XAML 命名空间关联用于 XAML 的推荐前缀。
我们可以给程序集定义一个访问的链接,这个链接只有在其他程序集中才可以使用,这时我们在 WpfAppResource2中调用Btn时,可以这么写:
<Window x:Class="WpfAppResource2.MainWindow" Title="MainWindow"
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"
xmlns:local="clr-namespace:WpfAppResource2"
xmlns:custom="http://schemas.bridge.com/WpfAppResource1/"
Width="800" Height="450" mc:Ignorable="d">
<Grid>
<custom:Btn Content="888"/>
</Grid>
</Window>
还可以更直接一点:
using System.Windows.Markup; [assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "WpfAppResource1")] namespace WpfAppResource1 { using System.Windows.Controls; using System.Windows; public class Btn : Button { static Btn() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Btn), new FrameworkPropertyMetadata(typeof(Btn))); } } }
<Window x:Class="WpfAppResource2.MainWindow" Title="MainWindow" 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" xmlns:local="clr-namespace:WpfAppResource2" Width="800" Height="450" mc:Ignorable="d"> <Grid> <Btn Content="888"/> </Grid> </Window>
因为"http://schemas.microsoft.com/winfx/2006/xaml/presentation" 是所用XAML中默认的名称空间。