当前位置:   article > 正文

【WPF绑定2】 INotifyPropertyChanged Or 依赖属性_wpf inotifypropertychanged 数据结构

wpf inotifypropertychanged 数据结构

在上一节,我们介绍了ListBox的基础绑定版,简单来说就是将一个数组结构赋值给了listbox的ItemsSource属性,就实现了绑定。

INotifyPropertyChanged

这次我们来看看,当属性绑定数据源之后,当数据源发生改变时,如何让属性跟随变换。

首先我们需要定义一个类Status,并实现接口 INotifyPropertyChanged 看名字就知道了它就是起一个通知的作用!

这个接口只定义了一个事件

  1. //
  2. // 摘要:
  3. // 通知客户端属性值已更改。
  4. public interface INotifyPropertyChanged
  5. {
  6. //
  7. // 摘要:
  8. // 在属性值更改时发生。
  9. event PropertyChangedEventHandler PropertyChanged;
  10. }

 所以,我们要做的就是实现这个事件

public event PropertyChangedEventHandler PropertyChanged;

然后为该事件定义一个触发函数!如果事件不为空,我就触发它!

注意该函数的参数为PropertyChangedEventArgs ,后面我们会看到他的用法。

  1. // 自定义事件触发函数!
  2. public void OnPropertyChanged(PropertyChangedEventArgs e)
  3. {
  4. if (PropertyChanged != null)
  5. PropertyChanged(this, e);
  6. }

事件PropertyChanged传入的两个参数,一个是类对象本身,和PropertyChangedEventArgs对象,构造PropertyChangedEventArgs对象要传入一个字符串(属性名称)!我们就是要通过这个字符串改变界面的显示。

比如我定义一个属性(它是一个字典):

1 一般会把事件触发直接写到属性的set中,这样在属性被修改时,就会触发该事件。

2 通过PropertyChangedEventArgs包装一个属性,一般传递的参数是属性名称的字符串,如果传递空字符串,wpf会通知所有绑定属性!

  1. //修改前
  2. //public Dictionary<ushort, float> DicData { get => dic_data; set => dic_data = value; }
  3. //修改后
  4. /// <summary>
  5. ///
  6. /// </summary>
  7. public Dictionary<ushort, ushort> DicRegData
  8. {
  9. get => dic_reg_data;
  10. // 仅仅修改字典的某个值,无法触发set,如: DicData[addr] = value
  11. set
  12. {
  13. dic_reg_data = value;
  14. // 一般传递的参数是propertyName,如果传递空字符串,wpf会通知所有绑定属性!
  15. OnPropertyChanged(new PropertyChangedEventArgs("DicRegData")); //后台数据发生变化时,前台数据可以跟着发生变化!
  16. }
  17. }

这里我插一段话,说下我对这个机制的理解,一般情况下,我们实现一个接口往往是实现一个方法或者说是函数。让后这个接口就会变成一个代理人,去调用这个方法,从而实现多态。实现了这个方法的类,往往就是多态中的一位成员(它一般就不会负责这个函数的调用)。

而这里,我们实现的是一个事件!并且负责触发这个事件,但是到目前为止,我们不知道谁会订阅这个事件?那么我猜想,应该是wpf的binding机制,订阅了这个事件,所以当wpf发现这个事件被触发之后,它要做的就是更新界面的信息!

通常情况下,都是我们订阅系统的事件,由系统触发事件。而这里恰恰相反,这种设计模式,我感觉是很有意思的。

而接下来,我们要做的就是将界面的某个元素的属性,绑定到后台数据源的某个属性!这样wpf才知道去通知谁?

假设,界面上的一个元素叫control,它有一个属性叫做BoolColorProperty,我们把该属性绑定到Status类DicRegData属性上面

  1. //实例化绑定对象
  2. Binding binding = new Binding();
  3. //设置要绑定源控件
  4. control.DataContext = status; //Status的对象
  5. //设置要绑定属性
  6. binding.Path = new PropertyPath("DicBitData");
  7. //绑定属性关联
  8. control.SetBinding(Status.BoolColorProperty, binding);

一般属性都有个DataContext 属性,就是为bingding准备的!我们会把数据源对象赋值给它。这样属性源就bingding好了。(DataContext类似集合类控件ItemsSource属性

接下来我们需要指定绑定Status中的哪个属性

binding.Path = new PropertyPath("DicBitData");

最后通过控件的SetBinding函数将界面上的属性,和后台对象的某个属性关联起来!

这些步骤当然是可以在Xaml中实现更简洁,但是这样写感觉会更清楚。

当然bingding还有更细微的操作,比如通知的方向性,转换器,转换器参数,通知的时机。以及整个流程有没有更方便的写法,我们在这个系列的文章后续在做介绍。


整体简明的写法:

  1. // 建议数据模型如果要做数据变化通知 ,使用INotifyPropertyChanged
  2. // 使用时是需要实例化的
  3. // DataClass dataClass=new DataClass();
  4. public class DataClass : INotifyPropertyChanged
  5. {
  6. public event PropertyChangedEventHandler PropertyChanged;
  7. private int _value;
  8. public int Value
  9. {
  10. get { return _value; }
  11. set
  12. {
  13. _value = value;
  14. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
  15. }
  16. }
  17. }

那么其实通过依赖属性,也可以实现相同的效果,但是更推荐这种写法!

接下来看看依赖属性的实现

依赖属性本身就是可以绑定,可通知的。

  1. public class Control : FrameworkElement
  2. {
  3. public string Value { get; set; }
  4. // 可以被绑定
  5. // 可以变化通知
  6. public int MyProperty
  7. {
  8. get { return (int)GetValue(MyPropertyProperty); }
  9. set
  10. {
  11. SetValue(MyPropertyProperty, value);
  12. }
  13. }
  14. public static readonly DependencyProperty MyPropertyProperty =
  15. DependencyProperty.Register("MyProperty", typeof(int), typeof(Control), new PropertyMetadata(0));
  16. }

但是,要实现依赖属性,必须直接或间接继承FrameworkElement(不然无法使用GetValue和SetValue),这是弊端之一(通知的方式只需要实现接口)。其二依赖属性使用了静态的属性,程序运行的过程中会一直存在与内存这是第二个弊端。

不过如果你本来是自定义控件,当然可以直接用依赖属性这种方式。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/567802
推荐阅读
相关标签
  

闽ICP备14008679号