WPF MVVM入门系列教程(二、依赖属性)
说明:本文是介绍WPF中的依赖属性功能,如果对依赖属性已经有了解了,可以欣赏后面的文章。为什么要介绍依赖属性
在WPF的数据绑定中,密不可分的就是依赖属性。而MVVM又是跟数据绑定紧密相连的,所以在学习MVVM之前,很有须要先学习一下依赖属性。
依赖属性(Depencency Property)是什么
先来看看MSDN上的表明:
WPF提供一组服务,这些服务可用于扩展类型的属性的功能。 这些服务统称为 WPF 属性系统。 由 WPF 属性系统提供支持的属性称为依赖属性。
普通点来说,WPF的依赖属性就是在.NET属性的底子上举行的扩展。它除了具备.NET属性的功能之外,还具备一些其它的扩展功能,如:值验证、默认值、值修改时的回调、转换器等。
我们先来看看.NET属性,也就是寻常我们在C#中使用的属性
1 public class CLRProperty
2 {
3 private int id;
4
5 public int Id
6 {
7 get => id;
8 set => id = value;
9 }
10 }
再来看看依赖属性
以Button控件的Content属性为例
1 public static readonly DependencyProperty ContentProperty = = DependencyProperty.Register("Content", typeof(object), typeof(ContentControl), new FrameworkPropertyMetadata((object)null, (PropertyChangedCallback)OnContentChanged));
2
3public object Content
4{
5 get
6 {
7 return GetValue(ContentProperty);
8 }
9 set
10 {
11 SetValue(ContentProperty, value);
12 }
13}
可以看到它也有一个get和set(即.NET的属性包装器),但是没有私有变量,而是通过GetValue和SetValue来完成取值和赋值。
依赖属性在使用上依赖属性和.NET属性无异:
例如有一个Button控件,定名为btn_Ok,我们可以在XAML中直接设置依赖属性的值
1 <Button Name="btn_Ok" Content="HelloWorld"></Button>
也可以在背景代码中设置
1btn_Ok.Content = "HelloWorld";
如何创建依赖属性
大多数在使用WPF原生控件的环境下,我们都是使用依赖属性,而非创建它。但是在自定义控件时,可能会需要用到依赖属性功能。
依赖属性对象不能直接被实例化,由于它没有公开的构造函数,只能通过DependencyProperty.Register()方法创建实例。
我们这里以自定义一个MyButton控件为例。
1、定义表现属性的对象
留意:这里使用了static readonly关键字,且对象定名时,后面都加上Property。
1 public static readonly DependencyObject ImageProperty;
2、注册依赖属性
1 ImageProperty = DependencyProperty.Register("Image", typeof(ImageSource), typeof(MyButton),new PropertyMetadata(null, OnImagePropertyChanged));
DependencyProperty.Register函数支持多种重载,下面这是一种比较常用的重载。
1 public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata);
下面来介绍一下它各个参数的作用
name:这个参数用于指定.NET属性包装器的名称
propertyType:指明依赖项属性存储什么类型的值,这里是ImageSource类型,代表图像数据
ownerType:指明此依赖属性的宿主是什么类型,这里是MyButton
typemetaData:指定此依赖属性的元数据,元数据定义依赖属性在应用于特定类型时的某些行为方面,包罗默认值、值更改时的回调等。上面的代码中,typeMetadata的第一个参数代表依赖属性的默认值,设置为null,第二个参数是在值更改时的回调函数,这里是调用OnImagePropertyChanged函数。
3、添加属性包装器
1 public ImageSource Image
2 {
3 get => (ImageSource)GetValue(ImageProperty);
4 set => SetValue(ImageProperty, value);
5 }
4、使用依赖属性
XAML
1 <local:MyButton x:Name="btn_Ok" Image="logo.jpg"/>
背景代码
1this.btn_Ok.Image = new BitmapImage(new Uri("logo.jpg", UriKind.Relative));
附加属性(Attached Property)
附加属性是一种特别的依赖属性。
来看看MSDN上的表明:
附加属性是一个 XAML概念。 附加属性答应为派生自 DependencyObject 的任何 XAML 元素设置额外的属性/值对,纵然该元素未在其对象模子中定义这些额外的属性。 额外的属性可举行全局访问。 附加属性通常定义为没有通例属性包装器的依赖属性的专用情势。
普通点来说,就是这个属性并不属于某个元素,但是通过附加属性可以设置上去。
附加属性在定义时是被定义到应用的谁人类,而非使用附加属性的谁人类。
一个简单的例子,例如一个Button控件在被计划出来以后,计划者也不知道它以后会被用于哪个布局容器,可能是Canvas,也可能 是Grid。
这个时候附加属性的作用就体现出来了:
当这个Button被放在Grid里时,就为它附加上Grid.Row和Grid.Column属性。
当这个Button被放在Canvas里时,就为它附加上Canvas.Left和Canvas.Top属性。
所以Grid.Row和Column是定义在Grid类中,而Canvas.Left和Canvas.Top是被定义在Canvas中。这一点跟前面的依赖属性有区别。
下面我们看一下附加属性代码结构,以Grid.Row为例
Grid.Row附加属性的定义如下:
1 public static readonly DependencyProperty RowProperty = DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid), new FrameworkPropertyMetadata(0, OnCellAttachedPropertyChanged), IsIntValueNotNegative);
2
3 public static int GetRow(UIElement element)
4 {
5 if (element == null)
6 {
7 throw new ArgumentNullException("element");
8 }
9
10 return (int)element.GetValue(RowProperty);
11 }
12
13 public static void SetRow(UIElement element, int value)
14 {
15 if (element == null)
16 {
17 throw new ArgumentNullException("element");
18 }
19
20 element.SetValue(RowProperty, value);
21 }
如何创建附加属性
这里我们以为每个控件增加一个Id依赖属性为例,这个属性仅做演示
1、定义表现属性的对象
1 public static readonly DependencyProperty IdProperty;
2、注册附加属性
1 IdProperty = DependencyProperty.RegisterAttached("Id", typeof(int), typeof(ControlExtension));
如果要设置默认值及值验证,可以参考这里,这里暂时不做详细的介绍,后面偶然间再补上。
3、添加"属性包装器"
这里和依赖属性的属性包装器不太一样,这里变成了Getxxx和Setxxx函数的情势。
1 public static int GetId(DependencyObject dependencyObject)
2 {
3 return (int)dependencyObject.GetValue(IdProperty);
4 }
5
6 public static void SetId(DependencyObject dependencyObject,int value)
7 {
8 dependencyObject.SetValue(IdProperty, value);
9 }
4、使用附加属性
XAML赋值
1 <Window x:Class="IntroductionToAttachedProperty.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:IntroductionToAttachedProperty"
7 mc:Ignorable="d"
8 Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
9 <Grid Name="grid"<strong> local:ControlExtension.Id="100"</strong>>
10
11 </Grid>
12 </Window>
在背景代码中获取附加属性的值
1 private void Window_Loaded(object sender, RoutedEventArgs e)
2 {
3 MessageBox.Show(ControlExtension.GetId(this.grid).ToString());
4 }
在背景代码中赋值
1ControlExtension.SetId(this.grid, 100);
总结
WPF的属性在MVVM模式开辟中非常关键,所以有须要了解清楚。本文仅介绍了依赖属性和附加属性的底子概念,对于把握MVVM模式底子开辟来说,已经够用。
本文不包罗依赖属性内存存储方式、属性取值优先级、属性默认值、属性值更改回调、属性验证等概念,在后面的文章中再举行增补。
参考资料
https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/properties/dependency-properties-overview?view=netdesktop-8.0&source=recommendations
示例代码
https://github.com/zhaotianff/WPF-MVVM-Beginner/tree/main/2_DependencyProperty
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]