【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),这是弊端之一(通知的方式只需要实现接口)。其二依赖属性使用了静态的属性,程序运行的过程中会一直存在与内存这是第二个弊端。

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code bean

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值