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
,不是吗?”然后,给出了简短的答案:虽然你可以这样做,但通常不推荐,因为你将失去内置的EqualityComparer
。EqualityComparer
的作用是确保如果设置了多次相同的值,INotifyPropertyChanged
接口只会在值第一次改变时触发PropertyChanged
事件。
接下来,通过一个代码示例来说明直接调用RaisePropertyChanged
的问题:
public class ViewAViewModel : BindableBase
{
private string _message;
public string Message
{
get => _message;
set
{
// 不要这样做!
_message = value;
RaisePropertyChanged();
}
}
}
这种代码在生产环境中很常见,但这种代码是有根本缺陷的,过于冗长,并且会导致不必要的PropertyChanged
事件被触发。因此,你应该始终围绕SetProperty
方法来构建你的代码流程。
总结一下,使用SetProperty
而不是直接调用RaisePropertyChanged
的原因是:
SetProperty
内置了EqualityComparer
,可以避免在属性值没有实际改变时触发PropertyChanged
事件。- 直接调用
RaisePropertyChanged
会导致代码过于冗长,并且可能会引发不必要的事件。 - 使用
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 方法:
- 这两个方法是用来响应激活状态变化的虚拟保护方法。你可以在派生类中重写这些方法来执行特定的逻辑。
相关链接
- 介绍(Introduction)
- 命令(Commands)
- 命令(Commanding)
- 复合命令(Composite Commands)
- 异步命令(Async Commands)
- 错误处理(Error Handling)
- 依赖注入(Dependency Injection)
- 依赖注入(Dependency Injection)
- 注册类型(Registering Types)
- 处理解析错误
- ContainerLocator
- MVVM
- BindableBase