質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

922閲覧

XAML Class プロパティの更新タイミングで処理を呼び出したい。

hogehage

総合スコア4

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2022/12/09 08:25

編集2022/12/09 09:15

XAML class プロパティをBindingしているが、class プロパティのsetterが機能しない現象に困っています。
Classプロパティが更新されたタイミングで処理を呼び出したいです。

Data型のclass プロパティであるDtのAプロパティをTextBoxにBindingして表示しています。

困っていること

Textboxに「あいうえお」を入力すると、DtプロパティのSetterを通って、DataクラスのAプロパティのSetterに入るものだと思っていましたが、直接DataクラスのAプロパティのSetterに入ってしまいます。
Classプロパティが更新されたタイミングで処理を行いたいのです。

実現したいこと

Dt.Aプロパティが更新されたタイミングでDtプロパティのSetterを呼び出すようにしたい
→Dt.Aプロパティが更新されたタイミングで処理がしたい。

試したこと

こういうことなのかなと思っています。
関連質問 https://teratail.com/questions/2ukhbfvrlebare

期待出力

Debug.WriteLine("dt setter working!!");

ソース

XAML:View.xaml

1 <TextBox Text="{Binding Path=Dt.A}" Width="100" />

C#:ViewModel.cs

1pubic class ViewModel{ 2 private Data dt = new Data(); 3 4 public Data Dt 5 { 6 get => dt; 7 set 8 { 9 dt = value; 10 //何らかの処理 11 Debug.WriteLine("dt setter working!!"); 12 //INotifyPropertyChangedを実装したもの 13 NotifyPropertyChanged(); 14 } 15 } 16}

C#:Data.cs

1public class Data 2{ 3 public string A { get; set; } 4 public int B { get; set; } 5}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KOZ6.0

2022/12/09 09:03 編集

.NET Framework なら RealProxy、.NET Core/.NET なら DispatchProxy を使って、それなりのコードを書けばプロパティを実装するだけで実現できるでしょう。 もしかしたら誰かが作って公開してくれてるかもしれないので探してみては?
hogehage

2022/12/09 09:13

Proxyは知らなかったです。勉強になります。
Zuishin

2022/12/09 10:44

Data をイミュータブル(たとえば Record)にし、dt.A を変更するかわりに dt ごと変更するのが今風かもしれません。
guest

回答2

0

ベストアンサー

Dt.Aプロパティが更新されたタイミングで処理がしたい。

Dataのほうを(も)INotifyPropertyChangedにすることはできないんでしょうか?
そうすればViewModel側で変更をリッスンできますが...(Dt2

setterで処理をするアプローチをいったん捨てる必要があるかと思っています。

TextBoxTextChangedを、ビヘイビアで呼び出すことは可能です(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

1using System.ComponentModel; 2using System.Diagnostics; 3using System.Windows; 4using System.Windows.Controls; 5using CommunityToolkit.Mvvm.ComponentModel; 6using CommunityToolkit.Mvvm.Input; 7 8namespace Q4z4o4vza1axlqk; 9 10 11public 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 71public class Data 72{ 73 public string? A { get; set; } 74} 75 76public partial class Data2 : ObservableObject 77{ 78 [ObservableProperty] private string? a; 79} 80 81public 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

投稿2022/12/09 10:58

編集2022/12/14 02:21
TN8001

総合スコア9441

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

前のスレッド https://teratail.com/questions/2ukhbfvrlebare の回答で解決したと思ってましたが、理解できませんでしたか? 

前のスレッドでも書きましたが、Dt.A に値を代入しても Dt プロパティの setter は通らないので、setter の中のコード、

C#

1dt = value; 2//何らかの処理 3Debug.WriteLine("dt setter working!!"); 4//INotifyPropertyChangedを実装したもの 5NotifyPropertyChanged();

は実行されないのが分かりませんか?

今の構造で、Dt.A に値を代入した際に何か処理をしたいのなら、Data クラスの A プロパティの setter で処理するほか手はなさそうですが、そういうことはできないのですか?

投稿2022/12/09 08:52

編集2022/12/09 08:58
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hogehage

2022/12/09 09:17 編集

何度もご回答ありがとうございます。 >前のスレッドでも書きましたが、Dt.A に値を代入しても Dt プロパティの setter は通らないので~ は理解しています。前回はXAMLを絡めて質問していなかったので別質問にしました。 >Data クラスの A プロパティの setter で処理するほか手はなさそうですが、そういうことはできないのですか? Dataクラスのsetterで処理をする場合、密結合になると思ったため、その案を見送りました。 頭が整理できていなくて申し訳ないです。 最終的に実現したいことは「Dt.Aプロパティが更新されたタイミングで処理がしたい。」ということです。 質問した後も考えていますが、setterで処理をするアプローチをいったん捨てる必要があるかと思っています。 この質問だとわかりづらいですね。修正します。
退会済みユーザー

退会済みユーザー

2022/12/10 00:36 編集

回答の繰り返しになりますが・・・ 何にせよ今の構造では、 > Dt.Aプロパティが更新されたタイミングで処理がしたい。 と言われても、Dt.A に値を代入しても Dt プロパティの setter は通らないので何ともなりません。 > Dataクラスのsetterで処理をする場合、密結合になると思ったため、その案を見送りました。 ViewModel クラスの Dt プロパティの setter なら密結合にならないという話がわかりませんが、今の構造のまま何とかするなら、質問者さんの言う「蜜結合」になるのは諦めて、Data クラスの A プロパティの setter で処理する方向に進むという選択肢は考えられませんか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問