Bootstrap

【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. 示例代码

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的问题:

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.在属性变化时执行委托

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

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

相关链接

;