【WPF绑定2】 INotifyPropertyChanged Or 依赖属性
在上一节,我们介绍了ListBox的基础绑定版,简单来说就是将一个数组结构赋值给了listbox的ItemsSource属性,就实现了绑定。
INotifyPropertyChanged
这次我们来看看,当属性绑定数据源之后,当数据源发生改变时,如何让属性跟随变换。
首先我们需要定义一个类Status,并实现接口 INotifyPropertyChanged 看名字就知道了它就是起一个通知的作用!
这个接口只定义了一个事件
//
// 摘要:
// 通知客户端属性值已更改。
public interface INotifyPropertyChanged
{
//
// 摘要:
// 在属性值更改时发生。
event PropertyChangedEventHandler PropertyChanged;
}
所以,我们要做的就是实现这个事件
public event PropertyChangedEventHandler PropertyChanged;
然后为该事件定义一个触发函数!如果事件不为空,我就触发它!
注意该函数的参数为PropertyChangedEventArgs ,后面我们会看到他的用法。
// 自定义事件触发函数!
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
事件PropertyChanged传入的两个参数,一个是类对象本身,和PropertyChangedEventArgs对象,构造PropertyChangedEventArgs对象要传入一个字符串(属性名称)!我们就是要通过这个字符串改变界面的显示。
比如我定义一个属性(它是一个字典):
1 一般会把事件触发直接写到属性的set中,这样在属性被修改时,就会触发该事件。
2 通过PropertyChangedEventArgs包装一个属性,一般传递的参数是属性名称的字符串,如果传递空字符串,wpf会通知所有绑定属性!
//修改前
//public Dictionary<ushort, float> DicData { get => dic_data; set => dic_data = value; }
//修改后
/// <summary>
/// 字
/// </summary>
public Dictionary<ushort, ushort> DicRegData
{
get => dic_reg_data;
// 仅仅修改字典的某个值,无法触发set,如: DicData[addr] = value
set
{
dic_reg_data = value;
// 一般传递的参数是propertyName,如果传递空字符串,wpf会通知所有绑定属性!
OnPropertyChanged(new PropertyChangedEventArgs("DicRegData")); //后台数据发生变化时,前台数据可以跟着发生变化!
}
}
这里我插一段话,说下我对这个机制的理解,一般情况下,我们实现一个接口往往是实现一个方法或者说是函数。让后这个接口就会变成一个代理人,去调用这个方法,从而实现多态。实现了这个方法的类,往往就是多态中的一位成员(它一般就不会负责这个函数的调用)。
而这里,我们实现的是一个事件!并且负责触发这个事件,但是到目前为止,我们不知道谁会订阅这个事件?那么我猜想,应该是wpf的binding机制,订阅了这个事件,所以当wpf发现这个事件被触发之后,它要做的就是更新界面的信息!
通常情况下,都是我们订阅系统的事件,由系统触发事件。而这里恰恰相反,这种设计模式,我感觉是很有意思的。
而接下来,我们要做的就是将界面的某个元素的属性,绑定到后台数据源的某个属性!这样wpf才知道去通知谁?
假设,界面上的一个元素叫control,它有一个属性叫做BoolColorProperty,我们把该属性绑定到Status类的DicRegData属性上面。
//实例化绑定对象
Binding binding = new Binding();
//设置要绑定源控件
control.DataContext = status; //Status的对象
//设置要绑定属性
binding.Path = new PropertyPath("DicBitData");
//绑定属性关联
control.SetBinding(Status.BoolColorProperty, binding);
一般属性都有个DataContext 属性,就是为bingding准备的!我们会把数据源对象赋值给它。这样属性源就bingding好了。(DataContext类似集合类控件的ItemsSource属性)
接下来我们需要指定绑定Status中的哪个属性?
binding.Path = new PropertyPath("DicBitData");
最后通过控件的SetBinding函数将界面上的属性,和后台对象的某个属性关联起来!
这些步骤当然是可以在Xaml中实现更简洁,但是这样写感觉会更清楚。
当然bingding还有更细微的操作,比如通知的方向性,转换器,转换器参数,通知的时机。以及整个流程有没有更方便的写法,我们在这个系列的文章后续在做介绍。
整体简明的写法:
// 建议数据模型如果要做数据变化通知 ,使用INotifyPropertyChanged
// 使用时是需要实例化的
// DataClass dataClass=new DataClass();
public class DataClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _value;
public int Value
{
get { return _value; }
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}
}
那么其实通过依赖属性,也可以实现相同的效果,但是更推荐这种写法!
接下来看看依赖属性的实现
依赖属性本身就是可以绑定,可通知的。
public class Control : FrameworkElement
{
public string Value { get; set; }
// 可以被绑定
// 可以变化通知
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set
{
SetValue(MyPropertyProperty, value);
}
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(Control), new PropertyMetadata(0));
}
但是,要实现依赖属性,必须直接或间接继承FrameworkElement(不然无法使用GetValue和SetValue),这是弊端之一(通知的方式只需要实现接口)。其二依赖属性使用了静态的属性,程序运行的过程中会一直存在与内存这是第二个弊端。
不过如果你本来是自定义控件,当然可以直接用依赖属性这种方式。
作者:宋桓公
出处:http://www.cnblogs.com/douzi2/
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。