赞
踩
在上一节,我们介绍了ListBox的基础绑定版,简单来说就是将一个数组结构赋值给了listbox的ItemsSource属性,就实现了绑定。
这次我们来看看,当属性绑定数据源之后,当数据源发生改变时,如何让属性跟随变换。
首先我们需要定义一个类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),这是弊端之一(通知的方式只需要实现接口)。其二依赖属性使用了静态的属性,程序运行的过程中会一直存在与内存这是第二个弊端。
不过如果你本来是自定义控件,当然可以直接用依赖属性这种方式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。