私はWPFプログラミング環境ではかなり新しいです。 MVVM設計パターンを使用してプログラムを作成しようとしています。
私はいくつかの研究を行い、それに関連するいくつかの記事を読みました。
ViewModelBase
私はそれが何であるかを知っています..しかし、私自身のViewModelBaseを書き出すことができるように、どこから始めるべきかを具体的に知っているかもしれませんか?のように...複雑になりすぎることなく、何が起こっているのかを本当に理解しています。ありがとうございました :)
内部で何が起こっているのかわからない場合は、MVVMフレームワークを使用する価値はありません。
それでは、ステップバイステップで独自のViewModelBaseクラスを構築しましょう。
ViewModelBaseは、すべてのビューモデルに共通のクラスです。すべての一般的なロジックをこのクラスに移動しましょう。
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)
は推奨されないことに注意してください。
次のように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);
}
}
MVVMを実装するためのいくつかのnugetパッケージがあります
私にとっては、MVVMライトはコードサンプルを提供するため、初心者にとって簡単です。
そのため、このnugetパッケージをインストールし、生成されたコードを確認し、必要に応じて詳細な説明を入手してください。
このBaseVewModel が好きです。ビューモデルにきれいなスタイルを与えます。さまざまな「前」と「後」の比較を確認してください。もちろん、必須ではありません。BaseViewModelが提供する機能が気に入らない場合は、使用しないでください。または、ソースコードがあるため、変更します。特に、変更通知を使用してプロパティを実装するには3つの異なる方法があることに注意してください-あなたが理解/快適に感じる洗練度のレベルを選択してください。
以下のクラスは、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デザイナー内で実行しているかどうかを判断するユーティリティメソッドです。