C#中所有的类都可以在资源中定义实例
C#常用类型的资源定义
注意,.Net环境下,运行库程序集为System.Runtime
,Framework环境下则为mscorlib
。
一、资源的定义
值类型资源的定义
<Window ......
xmlns:sys="clr-namespace:System;assembly=System.Runtime"//如果是Framework环境下则为clr-namespace:System;assembly=mscorlib
......
>
<Window.Resources>
<sys:Double x:Key="value">200</sys:Double>
</Window.Resources>
......
</Window>
数组资源的定义
<Window ......
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
......
>
<Window.Resources>
<!--List<int> datas-->
<x:Array x:Key="datas" Type="sys:Int32">
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
<sys:Int32>3</sys:Int32>
<sys:Int32>4</sys:Int32>
<sys:Int32>5</sys:Int32>
</x:Array>
</Window.Resources>
......
</Window>
二、资源的引用
静态引用
语法:{StaticResource ResourceKey=keyName}
。
ResourceKey
可以省略,即可以写成{StaticResource keyName}
<Grid>
<Button Content="button1" Width="{StaticResource ResourceKey=value}" Height="{StaticResource ResourceKey=value}"/>
</Grid>
动态引用
语法:{DynamicResource ResourceKey=keyName}
。
<Grid>
<Button Content="button1" Width="{DynamicResource ResourceKey=value}" Height="{DynamicResource ResourceKey=value}"/>
</Grid>
静态VS动态
针对同一个资源,可以使用静态或者动态引入,两者的区别在于,静态引入后,如果运行过程中对资源进行改变,xaml中的对应值是不会有改变的。而动态引入的话,会对该资源进行监听,如果运行过程中对资源进行了改变,xaml中的对应值会发生变化。
动态引用可以运用在文字、主题等的动态替换上。
此外,有时候需要在运行时才能加载到资源的,也要使用动态引用才更为合理。
自定义类型的资源定义
要将自定义类型对象作为WPF资源,具体有如下3个步骤:
- 创建自定义类型
namespace WPFResource
{
public class MyResource
{
public string name { get; set; } = "Schuyler";
}
}
- 引入该类型所在的命名空间。
- 在
Window.Resources
元素中进行引用。
<Window ......
xmlns:local="clr-namespace:WPFResource"
......
>
<Window.Resources>
<local:MyResource x:Key="myResource" name="Schuyler"/>
</Window.Resources>
......
</Window>
对象数据提供程序-ObjectDataProvider(重要)
ObjectDataProvider
是WPF中的一个数据提供程序,可以帮助我们在WPF中创建数据对象。
以上文中的自定义类型为例,可以通过ObjectDataProvider
在视图中创建资源
-
示例
<Window ...... xmlns:local="clr-namespace:WPFResource" ...... > <Window.Resources> <ObjectDataProvider ObjectType="local:MyResource" x:Key="myResource"/> </Window.Resources> ...... </Window>
如果想要创建带参构造函数的对象,可以使用ObjectDataProvider.ConstructorParameters
设置构造函数的参数。
-
示例
public class MyResource { public string Name { get; set; } public MyResource(string name) { Name = name; } }
<Window ...... xmlns:local="clr-namespace:WPFResource" xmlns:sys="clr-namespace:System;assembly=System.Runtime" ...... > <Window.Resources> <ObjectDataProvider ObjectType="local:MyResource" x:Key="myResource"> <ObjectDataProvider.ConstructorParameters> <sys:String>Schuyler</sys:String> </ObjectDataProvider.ConstructorParameters> </ObjectDataProvider> </Window.Resources> ...... </Window>
资源作用域
在上文中可以看到,资源都是在Resources
属性下进行定义的,而Resources
是FrameworkElement
类中的属性成员,几乎所有的WPF控件都为该类的子类,也就是说,基本上所有容器控件都可以使用Resources
属性来进行资源的定义。这也就产生了不同的作用域,上文中是使用了Windows
控件的Resources
属性进行资源定义的,也就是该窗体中的所有控件都能访问到所定义的资源。
此外,WPF在使用资源时,会一层一层的向上寻找,当前控件中没有对应资源就找父类中的资源,如果还是没有就找父类的父类中的资源,一直到当前XAML文件的最顶级元素中的资源,如果在没有,就会跳转到App.xaml文件中的资源寻找。
- 总结下来的资源寻找顺序为:自身资源->父级资源->……->窗口资源->应用程序资源->框架系统资源。
这里有个需要注意的地方,WPF在进行渲染时,也是一层层从顶级元素向内加载的,因此如果希望在某个控件的属性中使用该控件定义的资源,那么该属性就必须放置在定义资源之后。
- 在定义资源之前引用资源,此时属性加载,而该控件的资源定义还未加载,因此直接引用了父类的资源。
<Window x:Class="WPFResource.MainWindow"
......
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WPFResource"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<sys:Double x:Key="value">500</sys:Double>
</Window.Resources>
<Border Height="{StaticResource value}">
<Border.Resources>
<sys:Double x:Key="value">200</sys:Double>
</Border.Resources>
</Border>
</Window>
- 在定义资源之后引用资源,此时成功加载本控件定义的资源。
<Window.Resources>
<sys:Double x:Key="value">300</sys:Double>
</Window.Resources>
<Border>
<Border.Resources>
<sys:Double x:Key="value">200</sys:Double>
</Border.Resources>
<Border.Height>
<StaticResource ResourceKey="value"/>
</Border.Height>
</Border>
如果希望定义的资源,在整个应用中的所有xaml文件都能够访问到,可以将其定义在App.xaml的Resource
中。
<Application ......
xmlns:sys="clr-namespace:System;assembly=mscorlib"
......
>
<Application.Resources>
<sys:Double x:Key="value">200</sys:Double>
</Application.Resources>
</Application>