web-dev-qa-db-ja.com

MVVMでViewModelBaseを記述する方法

私はWPFプログラミング環境ではかなり新しいです。 MVVM設計パターンを使用してプログラムを作成しようとしています。

私はいくつかの研究を行い、それに関連するいくつかの記事を読みました。

ViewModelBase

私はそれが何であるかを知っています..しかし、私自身のViewModelBaseを書き出すことができるように、どこから始めるべきかを具体的に知っているかもしれませんか?のように...複雑になりすぎることなく、何が起こっているのかを本当に理解しています。ありがとうございました :)

22
DriLLFreAK100

内部で何が起こっているのかわからない場合は、MVVMフレームワークを使用する価値はありません。

それでは、ステップバイステップで独自のViewModelBaseクラスを構築しましょう。

  1. ViewModelBaseは、すべてのビューモデルに共通のクラスです。すべての一般的なロジックをこのクラスに移動しましょう。

  2. ViewModelsはINotifyPropertyChangedを実装する必要があります(理由を理解していますか?)

    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");と書くことができるため、コード内の文字列定数を回避できます。例:

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

    C#6にはnameof演算子があるため、OnPropertyChanged(() => SomeProperty)は推奨されないことに注意してください。

  3. 次のようにPropertyChangedを呼び出すプロパティを実装するのが一般的な方法です。

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

    ビューモデルベースでSetPropertyを定義しましょう:

    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イベントを呼び出すことにより、より具体的なクラスに拡張できるということです。

これはかなりそれです。これは、この段階でViewModelBaseに含める必要のあるすべてのものです。残りはプロジェクトによって異なります。たとえば、アプリはページベースのナビゲーションを使用し、ViewModelからのナビゲーションを処理するための独自のNavigationServiceを作成しました。そのため、ViewModelBaseクラスにNavigationServiceプロパティを追加できるため、必要に応じて、すべてのビューモデルからアクセスできます。

再利用性を高め、SRPを維持するために、BindableBaseというクラスを用意しました。これは、ここで行ったようにINotifyPropertyChangedの実装です。このクラスは普遍的であるため、すべてのWPF/UWP/Silverligt/WindowsPhoneソリューションでこのクラスを再利用します。

次に、各プロジェクトで、BindableBaseから派生したカスタムViewModelBaseクラスを作成します。

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>()   
}

ページベースのナビゲーションを使用するアプリがある場合は、ページビューモデルの基本クラスも指定します。

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

ダイアログ用に別のクラスを作成できます。

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);
    }
}
67
Liero

MVVMを実装するためのいくつかのnugetパッケージがあります

  1. MVVMライト
  2. MVVMクロス
  3. プリズム

私にとっては、MVVMライトはコードサンプルを提供するため、初心者にとって簡単です。

そのため、このnugetパッケージをインストールし、生成されたコードを確認し、必要に応じて詳細な説明を入手してください。

5
OrcusZ

このBaseVewModel が好きです。ビューモデルにきれいなスタイルを与えます。さまざまな「前」と「後」の比較を確認してください。もちろん、必須ではありません。BaseViewModelが提供する機能が気に入らない場合は、使用しないでください。または、ソースコードがあるため、変更します。特に、変更通知を使用してプロパティを実装するには3つの異なる方法があることに注意してください-あなたが理解/快適に感じる洗練度のレベルを選択してください。

2
Paul Smith

以下のクラスは、WPFプロジェクトでViewModelBaseとして使用できます。

public abstract class ViewModelBase : INotifyPropertyChanged
{
    /// <summary>
    /// Multicast event for property change notifications.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Checks if a property already matches a desired value.  Sets the property and
    /// notifies listeners only when necessary.
    /// </summary>
    /// <typeparam name="T">Type of the property.</typeparam>
    /// <param name="storage">Reference to a property with both getter and setter.</param>
    /// <param name="value">Desired value for the property.</param>
    /// <param name="propertyName">Name of the property used to notify listeners.This
    /// value is optional and can be provided automatically when invoked from compilers that
    /// support CallerMemberName.</param>
    /// <returns>True if the value was changed, false if the existing value matched the
    /// desired value.</returns>
    protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value)) return false;
        storage = value;
        // Log.DebugFormat("{0}.{1} = {2}", this.GetType().Name, propertyName, storage);
        this.OnPropertyChanged(propertyName);
        return true;
    }

    /// <summary>
    /// Notifies listeners that a property value has changed.
    /// </summary>
    /// <param name="propertyName">Name of the property used to notify listeners.  This
    /// value is optional and can be provided automatically when invoked from compilers
    /// that support <see cref="CallerMemberNameAttribute"/>.</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModelクラスの例は次のとおりです。

public class MyViewModel : ViewModelBase
{
    private int myProperty;
    public int MyProperty
    {
        get { return myProperty; }
        set { SetProperty(ref myProperty, value);
    }
}

ほとんどのMVVMフレームワークでは、基本ViewModelクラスに実際に含まれるコードはごくわずかです。通常は、INotifyPropertyChangedといくつかのヘルパー関数の実装のみです。

MVVM Lightの ViewModelBase および ObservableObject クラスのソースコードを見てください。 ObservableObjectは主にINotifyPropertyChangedの実装です-プロパティ名に「マジックストリング」ではなくラムダ式を使用します。 ViewModelBaseはObservableObjectを拡張し、ほとんどがVisual Studioデザイナー内で実行しているかどうかを判断するユーティリティメソッドです。

1
Peregrine