Dt.Aプロパティが更新されたタイミングで処理がしたい。
Data
のほうを(も)INotifyPropertyChanged
にすることはできないんでしょうか?
そうすればViewModel
側で変更をリッスンできますが...(Dt2
)
setterで処理をするアプローチをいったん捨てる必要があるかと思っています。
TextBox
のTextChanged
を、ビヘイビアで呼び出すことは可能です(Dt3
)
あるいはData.A
をラップするのも、ひとつの手かなと思います(Dt4A
)
.NET6です^^
xml
1 < Window
2 x: Class = " Q4z4o4vza1axlqk.MainWindow "
3 xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation "
4 xmlns: x = " http://schemas.microsoft.com/winfx/2006/xaml "
5 xmlns: behaviors = " http://schemas.microsoft.com/xaml/behaviors "
6 xmlns: local = " clr-namespace:Q4z4o4vza1axlqk "
7 Width = " 800 "
8 Height = " 450 " >
9 < Window.DataContext >
10 < local: ViewModel />
11 </ Window.DataContext >
12 < StackPanel >
13 <!-- Dt自体が変わるわけではないので当然検知できない! -->
14 < HeaderedContentControl Header = " Dt.A " >
15 < TextBox Text = " {Binding Dt.A, UpdateSourceTrigger=PropertyChanged} " />
16 </ HeaderedContentControl >
17
18 <!-- AがPropertyChangedしてくれればもちろん可能 -->
19 < HeaderedContentControl Header = " Dt2.A " >
20 < TextBox Text = " {Binding Dt2.A, UpdateSourceTrigger=PropertyChanged} " />
21 </ HeaderedContentControl >
22
23 <!-- 発想を変えてTextChangedをリッスン -->
24 < HeaderedContentControl Header = " Dt3.A " >
25 < TextBox x: Name = " textBox " Text = " {Binding Dt3.A, UpdateSourceTrigger=PropertyChanged} " >
26 < behaviors: Interaction.Triggers >
27 < behaviors: EventTrigger EventName = " TextChanged " >
28 < behaviors: InvokeCommandAction Command = " {Binding InvokeCommand} " CommandParameter = " {Binding Text, ElementName=textBox} " />
29 < behaviors: CallMethodAction MethodName = " CallMethod " TargetObject = " {Binding} " />
30 < behaviors: CallMethodAction MethodName = " CallMethod2 " TargetObject = " {Binding} " />
31 </ behaviors: EventTrigger >
32 </ behaviors: Interaction.Triggers >
33 </ TextBox >
34 </ HeaderedContentControl >
35
36 <!-- Dt.Aでのバインドをあきらめてラップする -->
37 < HeaderedContentControl Header = " Dt4A " >
38 < TextBox Text = " {Binding Dt4A, UpdateSourceTrigger=PropertyChanged} " />
39 </ HeaderedContentControl >
40 </ StackPanel >
41 </ Window >
cs
1 using System . ComponentModel ;
2 using System . Diagnostics ;
3 using System . Windows ;
4 using System . Windows . Controls ;
5 using CommunityToolkit . Mvvm . ComponentModel ;
6 using CommunityToolkit . Mvvm . Input ;
7
8 namespace Q4z4o4vza1axlqk ;
9
10
11 public partial class ViewModel : ObservableObject
12 {
13 [ ObservableProperty ] private Data dt = new Data ( ) ;
14 // ↓のようなコードが自動生成
15 //public Data Dt
16 //{
17 // get => dt;
18 // set
19 // {
20 // if (!Equals(dt, value))
21 // {
22 // dt = value;
23 // OnDtChanged(value);
24 // OnPropertyChanged();
25 // }
26 // }
27 //}
28
29 public Data2 Dt2 { get ; } = new Data2 ( ) ;
30
31 public Data Dt3 { get ; } = new Data ( ) ;
32
33 // Dt.Aでのバインドをあきらめてラップする
34 // [ObservableObject - .NET Community Toolkit | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/communitytoolkit/mvvm/observableobject#wrapping-a-non-observable-model)
35 private readonly Data dt4 = new Data ( ) ;
36 public string ? Dt4A
37 {
38 get => dt4 . A ;
39 set
40 {
41 if ( SetProperty ( dt4 . A , value , dt4 , ( d , a ) => d . A = a ) )
42 {
43 Debug . WriteLine ( $"Dt4A setter: { dt4 . A } " ) ;
44 }
45 }
46 }
47
48 public ViewModel ( ) => Dt2 . PropertyChanged += Dt2_PropertyChanged ;
49
50
51 // 呼ばれることはない
52 partial void OnDtChanged ( Data value ) => Debug . WriteLine ( $"OnDtChanged: { Dt . A } " ) ;
53
54 private void Dt2_PropertyChanged ( object ? sender , PropertyChangedEventArgs e )
55 => Debug . WriteLine ( $"Dt2_PropertyChanged: { Dt2 . A } " ) ;
56
57 [ RelayCommand ]
58 private void Invoke ( string ? value ) => Debug . WriteLine ( $"InvokeCommand: { value } " ) ;
59 // ↓のようなコードが自動生成
60 //private RelayCommand? invokeCommand;
61 //public IRelayCommand InvokeCommand => invokeCommand ??= new RelayCommand(Invoke);
62
63 // 直接メソッドも呼べる
64 public void CallMethod ( ) => Debug . WriteLine ( $"CallMethod: { Dt3 . A } " ) ;
65
66 // sender・argsも取れるが、System.Windows.Controlsに依存はさすがに気持ち悪い
67 public void CallMethod2 ( object sender , TextChangedEventArgs e )
68 => Debug . WriteLine ( $"CallMethod2: { ( sender as TextBox ) ! . Text } " ) ;
69 }
70
71 public class Data
72 {
73 public string ? A { get ; set ; }
74 }
75
76 public partial class Data2 : ObservableObject
77 {
78 [ ObservableProperty ] private string ? a ;
79 }
80
81 public partial class MainWindow : Window
82 {
83 public MainWindow ( ) => InitializeComponent ( ) ;
84 }
MVVM ソース ジェネレーター - .NET Community Toolkit | Microsoft Learn
NuGet Gallery | CommunityToolkit.Mvvm 8.0.0
NuGet Gallery | Microsoft.Xaml.Behaviors.Wpf 1.1.39