如何在 MVVM 中编写 ViewModelBase [英] How to write a ViewModelBase in MVVM

查看:28
本文介绍了如何在 MVVM 中编写 ViewModelBase的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 WPF 编程环境的新手.我正在尝试使用 MVVM 设计模式编写程序.

I'm pretty new in WPF programming environment. I'm trying to write a program out using MVVM design pattern.

我做了一些研究并阅读了一些与它相关的文章,很多时候我遇到了这个叫做

I've did some studies and read up some articles related to it and many of a time I came across this thing called

ViewModelBase

ViewModelBase

我知道它是什么..但是我可以具体知道我应该从哪里开始才能写出我自己的 ViewModelBase 吗?就像......真正了解正在发生的事情而不会变得太复杂.谢谢:)

I know what it is.. But may I know specifically where should I begin with to be able to write out my own ViewModelBase? Like... Really understanding what's happening without getting too complicated. Thank you :)

推荐答案

如果您不知道内部发生了什么,那么使用 MVVM 框架毫无价值.

It's worth nothing to use MVVM frameworks if you don't know what's going on inside.

那么让我们一步一步构建您自己的 ViewModelBase 类.

So let's go step by step and build your own ViewModelBase class.

  1. ViewModelBase 是所有视图模型的通用类.让我们将所有常见的逻辑移到这个类中.

  1. ViewModelBase is class common for all your viewmodels. Let's move all common logic to this class.

你的 ViewModel 应该实现 INotifyPropertyChanged(你明白为什么吗?)

Your ViewModels should implement INotifyPropertyChanged (do you understand why?)

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

[CallerMemberName] 属性不是必需的,但它允许您编写:OnPropertyChanged(); 而不是 OnPropertyChanged("SomeProperty");,因此您将避免代码中出现字符串常量.示例:

the [CallerMemberName] attribute is not required, but it will allow you to write: OnPropertyChanged(); instead of OnPropertyChanged("SomeProperty");, so you will avoid string constant in your code. Example:

public string FirstName
{
    set
    {
        _firtName = value;
        OnPropertyChanged(); //instead of OnPropertyChanged("FirstName") or OnPropertyChanged(nameof(FirstName))
    }
    get{ return _firstName;}
}

请注意,不再推荐 OnPropertyChanged(() => SomeProperty),因为我们在 C# 6 中有 nameof 运算符.

Please note, that OnPropertyChanged(() => SomeProperty) is no more recommended, since we have nameof operator in C# 6.

实现像这样调用 PropertyChanged 的​​属性是常见的做法:

It's common practice to implement properties that calls PropertyChanged like this:

public string FirstName
{
    get { return _firstName; }
    set { SetProperty(ref _firstName, value); }
}

让我们在您的视图模型库中定义 SetProperty:

Let's define SetProperty in your viewmodelbase:

protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = "")
{
    if (EqualityComparer<T>.Default.Equals(storage, value))
        return false;
    storage = value;
    this.OnPropertyChanged(propertyName);
    return true;
}

它只是在属性值改变并返回 true 时触发 PropertyChanged 事件.当值未更改并返回 false 时,它​​不会触发事件.基本思想是,SetProperty 方法是虚拟的,您可以在更具体的类中扩展它,例如触发验证,或通过调用 PropertyChanging 事件.

It simply fires PropertyChanged event when value of the property changes and returns true. It does not fire the event when the value has not changed and returns false. The basic idea is, that SetProperty method is virtual and you can extend it in more concrete class, e.g to trigger validation, or by calling PropertyChanging event.

这个不错.这是您的 ViewModelBase 在此阶段应包含的所有内容.其余的取决于您的项目.例如,您的应用程序使用页面基础导航,并且您编写了自己的 NavigationService 来处理来自 ViewModel 的导航.因此,您可以将 NavigationService 属性添加到您的 ViewModelBase 类中,这样您就可以根据需要从所有视图模型访问它.

This is pretty it. This is all your ViewModelBase should contain at this stage. The rest depends on your project. For example your app uses page base navigation and you have written your own NavigationService for handling navigation from ViewModel. So you can add NavigationService property to your ViewModelBase class, so you will have access to it from all your viewmodels, if you want.

为了获得更多的可重用性并保持 SRP,我有一个名为 BindableBase 的类,它几乎是我们在这里所做的 INotifyPropertyChanged 的​​实现.我在每个 WPF/UWP/Silverligt/WindowsPhone 解决方案中重用这个类,因为它是通用的.

In order to gain more reusability and keep SRP, I have class called BindableBase which is pretty much the implementation of INotifyPropertyChanged as we have done here. I reuse this class in every WPF/UWP/Silverligt/WindowsPhone solution because it's universal.

然后在每个项目中我创建从 BindableBase 派生的自定义 ViewModelBase 类:

Then in each project I create custom ViewModelBase class derived from BindableBase:

public abstract ViewModelBase : BindableBase
{
    //project specific logic for all viewmodels. 
    //E.g in this project I want to use EventAggregator heavily:
    public virtual IEventAggregator () => ServiceLocator.GetInstance<IEventAggregator>()   
}

如果我有使用基于页面导航的应用程序,我还会为页面视图模型指定基类.

if I have app, that uses page based navigation I also specify base class for page viewmodels.

public abstract PageViewModelBase : ViewModelBase
{
    //for example all my pages has title:
    public string Title {get; private set;}
}

我可以有另一个对话框类:

I could have another class for dialogs:

public abstract DialogViewModelBase : ViewModelBase
{
    private bool? _dialogResult;

    public event EventHandler Closing;

    public string Title {get; private set;}
    public ObservableCollection<DialogButton> DialogButtons { get; }

    public bool? DialogResult
    {
        get { return _dialogResult; }
        set { SetProperty(ref _dialogResult, value); }
    }

    public void Close()
    {
        Closing?.Invoke(this, EventArgs.Empty);
    }
}

这篇关于如何在 MVVM 中编写 ViewModelBase的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆