ObservableObject

これはObservableObject、オブジェクトとINotifyPropertyChangingインターフェイスを実装することによって観察できるオブジェクトのINotifyPropertyChanged基本クラスです。 これは、プロパティ変更通知をサポートする必要があるあらゆる種類のオブジェクトの開始点として使用できます。

プラットフォーム API:ObservableObject, TaskNotifier, TaskNotifier<T>

しくみ

ObservableObject には、次の主な機能があります。

  • これは、イベントとINotifyPropertyChangingイベントを公開するためのINotifyPropertyChanged基本実装をPropertyChangedPropertyChanging提供します。
  • 継承する型からプロパティ値を簡単に設定し、適切なイベントをObservableObject自動的に発生させるために使用できる一連SetPropertyのメソッドが用意されています。
  • このメソッドは、プロパティをSetPropertyAndNotifyOnCompletionSetProperty設定Taskし、割り当てられたタスクが完了したときに自動的に通知イベントを発生させる機能に似ています。
  • 通知イベントの発生方法を OnPropertyChanged カスタマイズするために、派生型でオーバーライドできるメソッドと OnPropertyChanging メソッドが公開されます。

Simple プロパティ

カスタム プロパティに通知サポートを実装する方法の例を次に示します。

public class User : ObservableObject
{
    private string name;

    public string Name
    {
        get => name;
        set => SetProperty(ref name, value);
    }
}

指定された SetProperty<T>(ref T, T, string) メソッドは、プロパティの現在の値をチェックし、異なる場合は更新し、関連するイベントも自動的に発生させます。 プロパティ名は属性を [CallerMemberName] 使用して自動的にキャプチャされるため、更新するプロパティを手動で指定する必要はありません。

観測不可能なモデルをラップする

たとえば、データベース項目を操作する場合の一般的なシナリオは、データベース モデルのプロパティを中継し、必要に応じてプロパティ変更通知を発生させるラップ "バインド可能" モデルを作成することです。 これは、インターフェイスを実装 INotifyPropertyChanged していないモデルに通知サポートを挿入する場合にも必要です。 ObservableObject は、このプロセスをより簡単にする専用のメソッドを提供します。 次の例では、 User 継承せずにデータベース テーブルを直接マッピングする ObservableObjectモデルです。

public class ObservableUser : ObservableObject
{
    private readonly User user;

    public ObservableUser(User user) => this.user = user;

    public string Name
    {
        get => user.Name;
        set => SetProperty(user.Name, value, user, (u, n) => u.Name = n);
    }
}

この場合、オーバーロードを SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) 使用しています。 シグネチャは前の署名よりも少し複雑です。これは、前のシナリオのようなバッキング フィールドにアクセスできない場合でも、コードを非常に効率的にするために必要です。 このメソッドシグネチャの各部分を詳しく見て、さまざまなコンポーネントの役割を理解することができます。

  • TModel は、ラップしているモデルの型を示す型引数です。 この場合は、クラス User になります。 これを明示的に指定する必要はありません。C# コンパイラでは、メソッドの呼び出し SetProperty 方法によって自動的に推論されます。
  • T は、設定するプロパティの型です。 同様に TModel、これは自動的に推論されます。
  • T oldValue は最初のパラメーターであり、この場合はラップしているそのプロパティの現在の値を渡すために使用 user.Name しています。
  • T newValue はプロパティに設定する新しい値であり、ここではプロパティセッター内の入力値である渡 valueしています。
  • TModel model はラップしているターゲット モデルです。この場合、フィールドに格納されているインスタンスを user 渡します。
  • Action<TModel, T> callback は、プロパティの新しい値が現在の値と異なり、プロパティを設定する必要がある場合に呼び出される関数です。 これは、ターゲット モデルと設定する新しいプロパティ値を入力として受け取るこのコールバック関数によって行われます。 この場合は、入力値(呼び出 nした値)をプロパティに Name 割り当てます(そう u.Name = nすることで)。 ここでは、現在のスコープから値をキャプチャしないようにし、コールバックへの入力として指定されたものとのみ対話することが重要です。これにより、C# コンパイラはコールバック関数をキャッシュし、いくつかのパフォーマンス向上を実行できます。 このため、ここでフィールドまたはvalueセッター内のパラメーターに直接アクセスuserするだけでなく、ラムダ式の入力パラメーターのみを使用しています。

このメソッドは SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) 、非常にコンパクトな API を提供しながら、ターゲット プロパティの取得と設定の両方を処理するため、これらのラップ プロパティを非常に簡単に作成します。

注意

LINQ 式を使用したこのメソッドの実装と比較して、特に状態パラメーターとコールバック パラメーターではなく型 Expression<Func<T>> のパラメーターを使用することで、この方法で実現できるパフォーマンスの向上は非常に重要です。 特に、このバージョンは LINQ 式を使用するバージョンよりも約 200 倍高速であり、メモリ割り当てをまったく行いません。

プロパティの処理Task<T>

プロパティがある場合は Task 、タスクが完了したら通知イベントも発生させ、バインディングが適切なタイミングで更新されるようにする必要があります。たとえば、タスクによって表される操作に読み込みインジケーターやその他の状態情報を表示します。 ObservableObject には、このシナリオの API があります。

public class MyModel : ObservableObject
{
    private TaskNotifier<int>? requestTask;

    public Task<int>? RequestTask
    {
        get => requestTask;
        set => SetPropertyAndNotifyOnCompletion(ref requestTask, value);
    }

    public void RequestValue()
    {
        RequestTask = WebService.LoadMyValueAsync();
    }
}

ここでは、メソッドは SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>, Task<T>, string) ターゲット フィールドの更新、新しいタスク (存在する場合) の監視、そのタスクの完了時に通知イベントの発生を処理します。 これにより、タスク プロパティにバインドするだけで、状態が変更されたときに通知を受け取ることができます。 これはTaskNotifier<T>、ターゲット Task<T> インスタンスをラップし、このメソッドに必要な通知ロジックを有効にすることによってObservableObject公開される特殊な型です。 この TaskNotifier 型は、一般 Task のみがある場合にのみ直接使用することもできます。

注意

このSetPropertyAndNotifyOnCompletionメソッドは、パッケージからのMicrosoft.Toolkit型の使用法をNotifyTaskCompletion<T>置き換えることを目的とします。 この型が使用されていた場合は、内部 Task (または Task<TResult>) プロパティのみに置き換えることができます。その後、メソッドを SetPropertyAndNotifyOnCompletion 使用して値を設定し、通知の変更を発生させることができます。 型によって NotifyTaskCompletion<T> 公開されるすべてのプロパティは、インスタンスで Task 直接使用できます。

  • MVVM Toolkitの動作を確認するには、サンプル アプリ (複数の UI フレームワークの場合) を確認してください。
  • 単体テストでさらに例を見つけることもできます。