【WPF】Prism学习(十)

Prism MVVM

1.BindableBase

1.1. BindableBase的作用

  • Prism库提供了一个基础类BindableBase,这个类实现了INotifyPropertyChanged接口。这个接口允许ViewModel(视图模型)通知视图(View)当属性(Property)发生变化时,以便视图可以更新显示。

1.2. Prism的接口驱动特性

  • Prism框架的许多功能,如响应生命周期事件、导航等,都是基于接口的。这意味着Prism并不强制要求开发者使用特定的基础类。

1.3. BindableBase的可选性

  • 尽管Prism提供了BindableBase作为INotifyPropertyChanged的实现,以帮助开发者,但它并不强制要求开发者必须使用这个类。开发者可以根据自己的需要选择任何基础类,甚至不使用任何基础类(尽管通常不推荐这样做)。

2.创建属性

在继承自BindableBase的类中创建属性,并确保这些属性的变化能够通知到用户界面(UI)。具体来说,它介绍了如何使用SetProperty方法来设置属性值,并确保属性有一个公共的属性和一个私有的后端字段(backing field)。

2.1. 创建属性(Creating Properties)

  • 当你在继承自BindableBase的类中创建属性时,如果你希望这些属性的变化能够通知到UI,你应该使用SetProperty方法来设置这些变化。
  • 每个属性都应该有一个公共的属性接口(供外部访问和设置),以及一个私有的后端字段,用于实际存储属性值。

2.2. 示例代码

csharp 复制代码
public class ViewAViewModel : BindableBase
{
    private string _message;
    public string Message
    {
        get => _message;
        set => SetProperty(ref _message, value);
    }
}
  • 代码示例展示了一个名为ViewAViewModel的类,它继承自BindableBase
  • 这个类中有一个名为_message的私有字符串字段,用于存储消息内容。
  • 同时,它有一个公共的字符串属性Message,用于获取和设置消息内容。
  • Message属性的set访问器中,使用了SetProperty方法来更新_message字段的值。SetProperty方法接受三个参数:一个引用传递的当前值(ref _message),新值(value),以及一个可选的回调委托,当属性值变化时执行。

2.3. SetProperty方法的作用

  • SetProperty方法不仅设置属性的新值,还自动比较新旧值,只有在值实际变化时才触发INotifyPropertyChanged事件,这样可以避免不必要的事件触发。
  • 如果直接设置值并调用RaisePropertyChanged,将失去这种内置的值比较功能,可能导致即使值未变化也触发事件。

3.为什么使用SetProperty

在实现MVVM模式时,使用SetProperty方法来设置属性值是更好的选择,而不是直接调用RaisePropertyChanged方法。

首先,提出了一个问题:"为什么使用SetProperty?毕竟你可以直接调用RaisePropertyChanged,不是吗?"然后,给出了简短的答案:虽然你可以这样做,但通常不推荐,因为你将失去内置的EqualityComparerEqualityComparer的作用是确保如果设置了多次相同的值,INotifyPropertyChanged接口只会在值第一次改变时触发PropertyChanged事件。

接下来,通过一个代码示例来说明直接调用RaisePropertyChanged的问题:

csharp 复制代码
public class ViewAViewModel : BindableBase
{
    private string _message;
    public string Message
    {
        get => _message;
        set
        {
            // 不要这样做!
            _message = value;
            RaisePropertyChanged();
        }
    }
}

这种代码在生产环境中很常见,但这种代码是有根本缺陷的,过于冗长,并且会导致不必要的PropertyChanged事件被触发。因此,你应该始终围绕SetProperty方法来构建你的代码流程。

总结一下,使用SetProperty而不是直接调用RaisePropertyChanged的原因是:

  1. SetProperty内置了EqualityComparer,可以避免在属性值没有实际改变时触发PropertyChanged事件。
  2. 直接调用RaisePropertyChanged会导致代码过于冗长,并且可能会引发不必要的事件。
  3. 使用SetProperty可以使代码更加简洁,并且遵循MVVM的最佳实践。

4.在属性变化时执行委托

csharp 复制代码
public abstract class ViewModelBase : BindableBase, IActiveAware
{
    private bool _isActive;
    public bool IsActive
    {
        get => _isActive;
        set => SetProperty(ref _isActive, value, () => {
            if (value)
                OnIsActive();
            else
                OnIsNotActive();
        });
    }

    protected virtual void OnIsActive() { }
    protected virtual void OnIsNotActive() { }
}

4.1. 代码示例

  • ViewModelBase 类继承自 BindableBase 类并实现了 IActiveAware 接口。
  • BindableBase 类是一个基类,它实现了 INotifyPropertyChanged 接口,允许对象通知绑定的UI元素属性值的变化。
  • IActiveAware 接口用于管理视图模型的激活状态。

4.2. IsActive 属性

  • IsActive 属性是一个布尔值,表示视图模型是否处于激活状态。
  • IsActive 属性的 set 访问器中,使用了 SetProperty 方法来更新 _isActive 私有字段的值,并注册了一个回调函数。
  • SetProperty 方法接受三个参数:一个引用传递的当前值、新值和一个可选的回调函数。

4.3. 回调函数

  • IsActive 属性的值被设置时,SetProperty 方法会检查新值和旧值是否相等。如果不相等,它会触发 PropertyChanged 事件,并执行提供的回调函数。
  • 在这个例子中,回调函数是一个匿名函数,它检查 IsActive 的新值:
    • 如果新值为 true,则调用 OnIsActive 方法。
    • 如果新值为 false,则调用 OnIsNotActive 方法。

4.4. OnIsActive 和 OnIsNotActive 方法

  • 这两个方法是用来响应激活状态变化的虚拟保护方法。你可以在派生类中重写这些方法来执行特定的逻辑。

相关链接

相关推荐
星星火柴93617 分钟前
关于“双指针法“的总结
数据结构·c++·笔记·学习·算法
小狗爱吃黄桃罐头18 分钟前
正点原子【第四期】Linux之驱动开发篇学习笔记-1.1 Linux驱动开发与裸机开发的区别
linux·驱动开发·学习
艾莉丝努力练剑1 小时前
【洛谷刷题】用C语言和C++做一些入门题,练习洛谷IDE模式:分支机构(一)
c语言·开发语言·数据结构·c++·学习·算法
武昌库里写JAVA2 小时前
JAVA面试汇总(四)JVM(一)
java·vue.js·spring boot·sql·学习
杜子不疼.3 小时前
《Python学习之字典(一):基础操作与核心用法》
开发语言·python·学习
小幽余生不加糖3 小时前
电路方案分析(二十二)适用于音频应用的25-50W反激电源方案
人工智能·笔记·学习·音视频
✎ ﹏梦醒͜ღ҉繁华落℘4 小时前
开发WPF项目时遇到的问题总结
wpf
..过云雨4 小时前
01.【数据结构-C语言】数据结构概念&算法效率(时间复杂度和空间复杂度)
c语言·数据结构·笔记·学习
myzzb4 小时前
基于uiautomation的自动化流程RPA开源开发演示
运维·python·学习·算法·自动化·rpa
非凡ghost7 小时前
AMS PhotoMaster:全方位提升你的照片编辑体验
windows·学习·信息可视化·软件需求