ObservePropertyChanging
1. 概要
ObservePropertyChanging は、INotifyPropertyChanging を実装したオブジェクトのプロパティ変更前の通知を Observable に変換する拡張メソッドです。
ObservePropertyChanged と同様のインターフェースを持ちますが、PropertyChanging イベントを使用するため、プロパティが実際に変更される前に通知が発火します。発行される値は通知時点の現在値(変更前の値)です。
ネストしたプロパティパスを最大 3 階層まで指定できます。
注意: これは拡張メソッドです。
source.ObservePropertyChanging(...)の形式で呼び出します。
2. シグネチャ
1 階層(直接プロパティ)
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対象オブジェクトの直接プロパティの変更前通知を監視します。
viewModel.ObservePropertyChanging(x => x.Name)2 階層(ネストプロパティ)
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 : INotifyPropertyChanging2 階層のネストしたプロパティの変更前通知を監視します。1 階層目は INotifyPropertyChanged、2 階層目は INotifyPropertyChanging を実装している必要があります。
3 階層(深いネストプロパティ)
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 : INotifyPropertyChanging3 階層までネストしたプロパティの変更前通知を監視します。最後の階層が INotifyPropertyChanging を実装している必要があります。
主なパラメータ
| パラメータ | 説明 |
|---|---|
propertySelector | 監視するプロパティを指定するラムダ式。シンプルなプロパティアクセス(x => x.Prop)である必要がある |
pushCurrentValueOnSubscribe | true(既定値)の場合、購読時に現在の値を即座に発行する |
cancellationToken | キャンセル時に監視を停止する |
3. マーブルダイアグラム
購読時に pushCurrentValueOnSubscribe が true であれば現在の値が即座に発行されます。その後、PropertyChanging イベントが発火するたびに、変更前の現在値が発行されます。
4. サンプルコード
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 との違い
ObservePropertyChanged は INotifyPropertyChanged の PropertyChanged イベントを使用し、プロパティが変更された後に新しい値を発行します。
ObservePropertyChanging は INotifyPropertyChanging の PropertyChanging イベントを使用し、プロパティが変更される前に現在の値(変更前の値)を発行します。
| 観点 | ObservePropertyChanged | ObservePropertyChanging |
|---|---|---|
| タイミング | 変更後 | 変更前 |
| 発行される値 | 新しい値 | 変更前の現在値 |
| 必要なインターフェース | INotifyPropertyChanged | INotifyPropertyChanging |
| 主な用途 | UI バインディング、値の追跡 | 変更の検証、Undo 履歴の記録 |