Skip to content

ObservePropertyChanged

1. 概要

ObservePropertyChanged は、INotifyPropertyChanged を実装したオブジェクトのプロパティ変更をイベント駆動(プッシュ型)で監視する拡張メソッドです。

ネストしたプロパティパスを最大 3 階層まで指定でき(例: x => x.Childc => c.Name)、中間オブジェクトが変わると自動的に監視先が切り替わります。

既定では購読時に現在の値を即座に発行します(pushCurrentValueOnSubscribe: true)。

注意: これは拡張メソッドです。source.ObservePropertyChanged(...) の形式で呼び出します。

2. シグネチャ

1 階層(直接プロパティ)

csharp
public static Observable<TProperty> ObservePropertyChanged<T, TProperty>(
    this T value,
    Func<T, TProperty> propertySelector,
    bool pushCurrentValueOnSubscribe = true,
    CancellationToken cancellationToken = default,
    [CallerArgumentExpression(nameof(propertySelector))] string? expr = null)
    where T : INotifyPropertyChanged

対象オブジェクトの直接プロパティを監視します。propertySelector にはシンプルなプロパティアクセス式(例: x => x.Name)を指定します。プロパティ名は CallerArgumentExpression により自動的に抽出されます。

csharp
viewModel.ObservePropertyChanged(x => x.Name)

2 階層(ネストプロパティ)

csharp
public static Observable<TProperty2> ObservePropertyChanged<T, TProperty1, TProperty2>(
    this T value,
    Func<T, TProperty1?> propertySelector1,
    Func<TProperty1, TProperty2> propertySelector2,
    bool pushCurrentValueOnSubscribe = true,
    CancellationToken cancellationToken = default,
    ...)
    where T : INotifyPropertyChanged
    where TProperty1 : INotifyPropertyChanged

2 階層のネストしたプロパティを監視します。中間プロパティ TProperty1INotifyPropertyChanged を実装している必要があります。中間オブジェクトが null に変わった場合は、発行が停止します。

csharp
viewModel.ObservePropertyChanged(
    x => x.SelectedItem,
    item => item.Name)

3 階層(深いネストプロパティ)

csharp
public static Observable<TProperty3> ObservePropertyChanged<T, TProperty1, TProperty2, TProperty3>(
    this T value,
    Func<T, TProperty1?> propertySelector1,
    Func<TProperty1, TProperty2?> propertySelector2,
    Func<TProperty2, TProperty3> propertySelector3,
    bool pushCurrentValueOnSubscribe = true,
    CancellationToken cancellationToken = default,
    ...)
    where T : INotifyPropertyChanged
    where TProperty1 : INotifyPropertyChanged
    where TProperty2 : INotifyPropertyChanged

3 階層までネストしたプロパティを監視します。すべての中間プロパティが INotifyPropertyChanged を実装している必要があります。

csharp
viewModel.ObservePropertyChanged(
    x => x.Department,
    d => d.Manager,
    m => m.Name)

主なパラメータ

パラメータ説明
propertySelector監視するプロパティを指定するラムダ式。シンプルなプロパティアクセス(x => x.Prop)である必要がある
pushCurrentValueOnSubscribetrue(既定値)の場合、購読時に現在の値を即座に発行する
cancellationTokenキャンセル時に監視を停止する

3. マーブルダイアグラム

ObservePropertyChanged のマーブルダイアグラム

購読時に pushCurrentValueOnSubscribetrue であれば現在の値が即座に発行されます。その後、PropertyChanged イベントが発火するたびに最新の値が発行されます。

4. サンプルコード

csharp
using R3;
using System.ComponentModel;

// === ViewModel の定義 ===
class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    private string _name = "";
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
        }
    }

    private int _age;
    public int Age
    {
        get => _age;
        set
        {
            _age = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Age)));
        }
    }
}

var vm = new MyViewModel { Name = "太郎", Age = 25 };

// === 1 階層: 直接プロパティの監視 ===
vm.ObservePropertyChanged(x => x.Name)
    .Subscribe(name => Console.WriteLine($"名前: {name}"));
// 出力(即座): 名前: 太郎

vm.Name = "花子";
// 出力: 名前: 花子

// === 初回値を発行しない ===
vm.ObservePropertyChanged(x => x.Age, pushCurrentValueOnSubscribe: false)
    .Subscribe(age => Console.WriteLine($"年齢: {age}"));
// この時点では出力なし

vm.Age = 30;
// 出力: 年齢: 30

// === 2 階層: ネストプロパティの監視 ===
// viewModel.ObservePropertyChanged(
//     x => x.SelectedItem,
//     item => item.Description)
//     .Subscribe(desc => Console.WriteLine($"説明: {desc}"));
// SelectedItem が変わると、新しい SelectedItem の Description の監視に自動切り替え

5. 補足

EveryValueChanged との違い

EveryValueChanged はポーリングベース(プル型)で、毎フレーム値を比較して変化を検知します。INotifyPropertyChanged の実装が不要なため、任意のクラスに使用できますが、フレームごとの比較コストが発生します。

ObservePropertyChanged はイベント駆動(プッシュ型)のため、プロパティが変更されたときだけ処理が実行されます。INotifyPropertyChanged を実装した ViewModel での使用に適しています。

ObservePropertyChanging との違い

ObservePropertyChangingINotifyPropertyChanging インターフェースを使用し、プロパティが変更される前に通知されます。変更前の値(現在の値)を取得したい場合に使用します。