前提・実現したいこと
「該当のソースコード」に記述したような階層的なクラスがあって、PropertyInt1項目を変更すると、何かしら計算してPropertyInt2項目に計算結果を反映したいです。
該当のソースコード
手元にビルドの環境がなく、雰囲気だけのコードですが記述してみました。
(実際の今のコードは自動実装プロパティが定義されているだけで、INotifyPropertyChangedなどは実装されていません。同期をとる処理を試すために修正したものが以下です。)
cs
1public class Class0 2{ 3 public Class1 PropertyClass1 { get; set; } = new Class1(); 4 public Class2 PropertyClass2 { get; set; } = new Class2(); 5 public Class0() 6 { 7 PropertyChangedEventManager.AddHandler(PropertyClass1.PropertyClass11, OnPropertyChanged, nameof(Class11.PropertyInt1)); 8 } 9 ~Class0() 10 { 11 PropertyChangedEventManager.RemoveHandler(PropertyClass1.PropertyClass11, OnPropertyChanged, nameof(Class11.PropertyInt1)); 12 } 13 public void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 14 { 15 if (!(sender is Class11)) return; 16 if (e.PropertyName == nameof(Class11.PropertyInt1)) 17 { 18 PropertyClass2.PropertyClass21.PropertyInt2 = PropertyClass1.PropertyClass11.PropertyInt1 * 2; 19 } 20 } 21} 22public class Class1 23{ 24 public Class11 PropertyClass11 { get; set; } = new Class11(); 25} 26public class Class11 : INotifyPropertyChanged 27{ 28 public event PropertyChangedEventHandler PropertyChanged; 29 private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") 30 { 31 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 32 } 33 private int _propertyInt1; 34 public int PropertyInt1 35 { 36 get => _propertyInt1; 37 set 38 { 39 if (_propertyInt1 == value) return; 40 _propertyInt1 = value; 41 NotifyPropertyChanged(); 42 } 43 } 44} 45public class Class2 46{ 47 public Class21 PropertyClass21 { get; set; } = new Class21(); 48} 49public class Class21 50{ 51 public int PropertyInt2 { get; set; } 52} 53 54public class Test 55{ 56 public void TestMethod() 57 { 58 var class0 = new Class0(); 59 class0.PropertyClass1.PropertyClass11.PropertyInt1 = 10; 60 // class0.PropertyClass2.PropertyClass21.PropertyInt2 == 20; 61 62 class0.PropertyClass1.PropertyClass11 = new Class11(); 63 class0.PropertyClass1.PropertyClass11.PropertyInt1 = 30; 64 // class0.PropertyClass2.PropertyClass21.PropertyInt2 == 60; // ← イベントが発生しないため60にはならない 65 } 66}
試したこと
プロパティの変更通知のイベントを購読して実装をしてみましたが、問題があるようでした。
PropertyClass1、PropertyClass11のプロパティ自体が変更された場合に、コンストラクタで購読設定したインスタンスは、現在保持しているインスタンスのものではなくなってしまい、PropertyInt1項目を変更してもイベントが発生しないことです。
※シリアル化を使ってClass0のインスタンスを生成しているところがあるのですが、シリアル化の動きとして、プロパティの初期値として指定してあるインスタンス(new Class1()
の部分)は、シリアル化で生成されたインスタンスで上書きされてしまうようでした。
そのため、Class0のコンストラクタで購読したインスタンスは、シリアル化から上書きされることによって、参照されない場所に消え去ってしまっていたようでした。
そこで、PropertyClass1、PropertyClass11が変更された場合にイベントを購読し直せば良いのではないかと考えました。
しかし、購読する項目が少ないうちは大丈夫そうですが、項目が増えた場合にメンテナンスしていけなそうに感じています。
次の記事の「リアクティブスパゲティ」という状況になりそうなイメージでしょうか。
初期化以外でSubscribeを書かない
MVVMの記事などを見るのですが、ビューとビューモデルについてだけしか記載されていないことが多く、モデルをどう実装するのかよく理解できていないところがあるのかもしれません。
次の記事の「Model間での変更通知」のセオリーのようなものが知りたいです。
※以下の記事では個人で開発されたStatefulModelというパッケージを使用することの説明がされていると思いますが、それ以外の開発者はこのパッケージを使用せずにMVVMを実現されていると思いますので、その場合のセオリーのようなものが知りたいです
イベント購読の問題
M-V-WhateverのWhateverではModelの変更通知をどう監視しますか?また、Model間での変更通知は?
最後に、PropertyInt1が設定されるのは画面から入力される時で、画面の項目にClass0クラスから辿ったパスがバインドされています。
ですので、「該当のソースコード」のTestクラスに記述したイメージで、PropertyInt1項目を設定しているところで、PropertyInt2を設定する処理も記述するということはできなそうだと思っています。
補足情報(FW/ツールのバージョンなど)
- Windows 10
- C# 7
- .NET Framework 4.5
- Visual Studio 2019
- WPF
回答1件
あなたの回答
tips
プレビュー