Skip to content

ObservePropertyChanging

1. 概要

ObservePropertyChanging は、INotifyPropertyChanging を実装したオブジェクトのプロパティ変更の通知を Observable に変換する拡張メソッドです。

ObservePropertyChanged と同様のインターフェースを持ちますが、PropertyChanging イベントを使用するため、プロパティが実際に変更される前に通知が発火します。発行される値は通知時点の現在値(変更前の値)です。

ネストしたプロパティパスを最大 3 階層まで指定できます。

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

2. シグネチャ

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

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

対象オブジェクトの直接プロパティの変更前通知を監視します。

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

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

csharp
public static Observable<TProperty2> ObservePropertyChanging<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 : INotifyPropertyChanging

2 階層のネストしたプロパティの変更前通知を監視します。1 階層目は INotifyPropertyChanged、2 階層目は INotifyPropertyChanging を実装している必要があります。

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

csharp
public static Observable<TProperty3> ObservePropertyChanging<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 : INotifyPropertyChanging

3 階層までネストしたプロパティの変更前通知を監視します。最後の階層が INotifyPropertyChanging を実装している必要があります。

主なパラメータ

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

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

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

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

4. サンプルコード

csharp
using R3;
using System.ComponentModel;

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

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

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

// === 変更前の値を取得 ===
vm.ObservePropertyChanging(x => x.Name)
    .Subscribe(name => Console.WriteLine($"変更前の名前: {name}"));
// 出力(即座): 変更前の名前: 太郎

vm.Name = "花子";
// 出力: 変更前の名前: 太郎(変更前の値が通知される)

vm.Name = "次郎";
// 出力: 変更前の名前: 花子(変更前の値が通知される)

// === Changed と Changing を組み合わせて変更の前後を取得 ===
vm.ObservePropertyChanging(x => x.Name, pushCurrentValueOnSubscribe: false)
    .Zip(vm.ObservePropertyChanged(x => x.Name, pushCurrentValueOnSubscribe: false))
    .Subscribe(pair => Console.WriteLine($"変更: {pair.First} → {pair.Second}"));

vm.Name = "三郎";
// 出力: 変更: 次郎 → 三郎

5. 補足

ObservePropertyChanged との違い

ObservePropertyChangedINotifyPropertyChangedPropertyChanged イベントを使用し、プロパティが変更された後に新しい値を発行します。

ObservePropertyChangingINotifyPropertyChangingPropertyChanging イベントを使用し、プロパティが変更される前に現在の値(変更前の値)を発行します。

観点ObservePropertyChangedObservePropertyChanging
タイミング変更後変更前
発行される値新しい値変更前の現在値
必要なインターフェースINotifyPropertyChangedINotifyPropertyChanging
主な用途UI バインディング、値の追跡変更の検証、Undo 履歴の記録