【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 方法

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

相关链接

相关推荐
Scout-leaf14 小时前
WPF新手村教程(三)—— 路由事件
c#·wpf
西岸行者2 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 天前
2026.2.25监控学习
学习
im_AMBER3 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode