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

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

新規登録して質問してみよう
ただいま回答率
85.48%
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

1回答

931閲覧

ボタンクリック時にテキストブロック内に文字列を表示する(ViewModel→View)

hiro.a

総合スコア28

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/05/15 03:23

編集2022/05/15 03:41

前提

仕事で使用しているC#のWPFの勉強の際に問題に直面したので質問させていただきます。

実現したいこと

実現したいことはボタンをクリック後にテキストブロック内に指定の文字列を表示することです。
WPF
MVVM構成
XAML
View.csとViewModel.csのみしか使用しない
Viewにはこれ以上の実装はしない。
ViewmoModel内だけで実装したい

発生している問題・エラーメッセージ

エラーは発生していません。 デバックした際に望んだ値は取得できています。 ただ、textblock内に表示だけができていません。

該当のソースコード

ViewModel

1 2using System.Diagnostics; 3using System; 4using System.Windows.Input; 5using System.ComponentModel; 6 7namespace WpfSample2Button 8{ 9 public class MainViewModel : INotifyPropertyChanged 10 { 11 12 public TestText Text { get; set; } 13 public event PropertyChangedEventHandler PropertyChanged; 14 MainViewModel mainViewModel = new MainViewModel(); 15 16 protected virtual void OnPropertyChanged(string name) 17 { 18 PropertyChanged(this, new PropertyChangedEventArgs(name)); 19 } 20 class MyCommand : ICommand 21 { 22 private Action<object> _action; 23 public event EventHandler CanExecuteChanged; 24 25 public MyCommand(Action<object> action) 26 { 27 _action = action; 28 } 29 public bool CanExecute(object parameter) 30 { 31 return true; 32 } 33 public void Execute(object parameter) 34 { 35 _action(parameter); 36 // parameterはnull 37 } 38 public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); 39 } 40 41 private ICommand _okButton; 42 public ICommand OkButton 43 { 44 get 45 { 46 return _okButton = new MyCommand((o) => 47 { 48 mainViewModel.PutText= new Text( new TestText { PutText = "hoge" }); 49 OnPropertyChanged("getText"); 50 } 51 52 ); 53 54 } 55 } 56 57 public class TestText 58 { 59 public string _putText; 60 public string PutText 61 { 62 63 get { _putText; } 64 set { _putText = Value; } 65 } 66 } 67 68 public MainViewModel() 69 { 70 71 } 72 } 73}

該当のソースコード

XAML

1<Window x:Class="WpfSample2Button.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfSample2Button" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Grid> 10 <Button Content="OK" Command="{Binding OkButton}" Width = "50" Height = "50" /> 11 </Grid> 12 <Grid> 13 <TextBlock Content="Text" Text="{Binding PutText Mode="OneWay" UpdateSourceTrigger=PropertyChanged}" Width = "50" Height = "50" /> 14 </Grid> 15</Window>

試したこと

値を渡す先のプロパティの変更通知(OnPropertyChanged)を実装しました。
ここも通るのですがOnPropertyChangedメソッド内のPropertyChangedがnullなのが気になってます。

今回のコードには不要だと思い記載はしておりませんが、そのほかにDateGrid内を選択すると選択対象の値を他のDateGrid内に表示するということをしています。
その内にもこのOnPropertyChangedでプロパティの変更通知をし完了しており
OnPropertyChangedメソッド内のPropertyChangedはnullではありませんでした。

補足情報(FW/ツールのバージョンなど)

TextBlockのTextプロパティ(getText)にバインドしています

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2022/05/15 03:29

研修や講習の課題なら講師に聞けないのですか? 業務の話なら、こういう所で聞くのは情報漏洩につながるので禁止されているのでは? 余計なお世話かもしれませんが・・・
hiro.a

2022/05/15 03:38 編集

誤解を招く書き方をして申し訳ございません。 業務でわからないことがでており、自己学習でコードを書いていた際に出てきた問題です
len_souko

2022/05/15 09:51

そもそも、C#があまりできないのではありませんか? まずはC#の文法を調べて最低限文法エラーが起きない状態まで修正してからの質問になりませんか? 質問文に提示されたソースコードは文法エラーが出ていますのでまるで動いたソースなのかの様に質問を書かれてもこちらとしてはコンパイルエラーのため動かす事が出来ないソースを提示して動いた結果の話をしている=問題が起きたソースとは異なるソースでしかありませんので、質問の減少が発生した原因がソースに記述されているかどうか判断できないという事です。せめて、質問の状況となるソースコードを提示してください。 以下は文法エラーの発生個所 > mainViewModel.PutText = new Text(new TestText { PutText = "hoge" }); ①mainViewModelにPutTextというプロパティはありません ②Textクラスは定義されていません > get { _putText; } ③値を返さないコードパスがあります ④割り当て、呼び出し、インクリメント、デクリメント、新しいオブジェクトの式のみがステートメントとして使用できます > set { _putText = Value; } ⑤現在のコンテキストに'Value'という名前は存在しません また、文法エラーではないけれど、おかしな点 ・必要もないのにクラス内でクラス定義を行っている(クラスの理解が足りていないようで、外側のクラス内から内部に定義したクラスのプロパティを外側のクラスのプロパティとしてアクセスしようとしている①) ・ひょっとしたらプロパティとクラス定義がごっちゃになってる?(②右辺はプロパティ名でnewしようとして、その引数にそのプロパティの型のクラスをnewしている) ・そもそも、TestTextクラスの存在意義は何? ・MainViewModelクラスのインスタンスフィールドにMainViewModelクラスのプロパティが存在して、newしている(無限ループになりませんか?)
guest

回答1

0

手元にVisual Studioはあるんでしょうか?(あるにしてはでたらめですし、ない状態でソラで書いたとすれば逆にすごいです^^;

ここも通るのですがOnPropertyChangedメソッド内のPropertyChangedがnullなのが気になってます。

nullだったらヌルポで落ちると思うのですが。。。
通常はそうならないように、PropertyChanged?.Invokeとします(CanExecuteChangedでやっていますね)

Executeparameterの話でしょうか?(でしたらCommandParameterを与えてないので当然です)

とりあえず提示コードを動かすならこんなんでしょうか。

xml

1<Window 2 x:Class="Qqnabh0pswfn0vv.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Qqnabh0pswfn0vv" 6 Width="800" 7 Height="450"> 8 <Window.DataContext> 9 <local:MainViewModel /> 10 </Window.DataContext> 11 <StackPanel> 12 <Button 13 Command="{Binding OkButton}" 14 CommandParameter="OK" 15 Content="OK" /> 16 <TextBlock Text="{Binding Text.PutText}" /> 17 <TextBlock Text="{Binding Text2.PutText}" /> 18 <TextBlock Text="{Binding Text3.PutText}" /> 19 <TextBlock Text="{Binding Text3.PutText2}" /> 20 </StackPanel> 21</Window>

cs

1using System; 2using System.ComponentModel; 3using System.Diagnostics; 4using System.Runtime.CompilerServices; 5using System.Windows; 6using System.Windows.Input; 7 8namespace Qqnabh0pswfn0vv 9{ 10 public class MainViewModel : INotifyPropertyChanged 11 { 12 public TestText Text { get; set; } 13 14 public TestText Text2 { get => _Text2; set => SetProperty(ref _Text2, value); } 15 private TestText _Text2; 16 17 public TestText Text3 { get; } = new TestText(); 18 19 20 private ICommand _okButton; 21 public ICommand OkButton 22 { 23 get 24 { 25 // こうではありません! 26 // まあ動かないわけではないがボタンを押すたびに、new MyCommandされるため全くの無駄 27 //return _okButton = new MyCommand((o) => 28 29 return _okButton ??= new MyCommand((o) => 30 { 31 Debug.WriteLine(o); // parameter 32 33 Text = new TestText { PutText = "hoge" }; 34 OnPropertyChanged("Text"); 35 36 // 通常はプロパティのセッターでPropertyChangedを発砲する 37 Text2 = new TestText { PutText = "fuga" }; 38 39 // TextではなくPutTextが変わる場合、TestText側でPropertyChangedを発砲する 40 Text3.PutText2 = "piyo"; 41 42 // これでも変わるといえば変わるが、普通はやらない(と思う) 43 Text3.PutText = "piyo"; 44 OnPropertyChanged("Text3"); 45 }); 46 47 // ??=(null合体割り当て演算子 C# 8.0以上)が使えない場合はこうなるが、 48 // そこまでやるんだったら「素直にコンストラクタに書けば?」と思いますw 49 //return _okButton ?? (_okButton = new MyCommand((o) => 50 //{ 51 // Text = new TestText { PutText = "hoge" }; 52 // OnPropertyChanged("Text"); 53 //})); 54 } 55 } 56 57 public ICommand OkButton2 { get; } 58 59 60 public class TestText : INotifyPropertyChanged 61 { 62 public string PutText { get; set; } 63 64 public string PutText2 { get => _PutText2; set => SetProperty(ref _PutText2, value); } 65 private string _PutText2; 66 67 68 #region INotifyPropertyChanged 69 public event PropertyChangedEventHandler PropertyChanged; 70 protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 71 protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) 72 { 73 if (Equals(storage, value)) return; 74 storage = value; 75 OnPropertyChanged(propertyName); 76 } 77 #endregion 78 } 79 80 public MainViewModel() 81 { 82 // 「素直にコンストラクタに書けば?」の例 83 OkButton2 = new MyCommand((o) => 84 { 85 Text = new TestText { PutText = "hoge" }; 86 OnPropertyChanged("Text"); 87 }); 88 } 89 90 91 #region INotifyPropertyChanged 92 public event PropertyChangedEventHandler PropertyChanged; 93 protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 94 95 // プロパティからOnPropertyChangedを呼びやすくするヘルパ(CallerMemberNameはC# 5.0以上) 96 protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) 97 { 98 if (Equals(storage, value)) return; 99 storage = value; 100 OnPropertyChanged(propertyName); 101 } 102 #endregion 103 104 #region ICommand 105 private class MyCommand : ICommand 106 { 107 private readonly Action<object> _action; 108 public event EventHandler CanExecuteChanged; 109 110 public MyCommand(Action<object> action) => _action = action; 111 public bool CanExecute(object parameter) => true; 112 public void Execute(object parameter) => _action(parameter); 113 public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); 114 } 115 #endregion 116 } 117 118 119 public partial class MainWindow : Window 120 { 121 public MainWindow() => InitializeComponent(); 122 } 123}

INotifyPropertyChangedICommand実装は、既存のものを使ったほうが楽じゃないですかね?(業務だとそうもいかないのかな?^^;

Introduction to the MVVM Toolkit - Windows Community Toolkit | Microsoft Docs

Getting Started | Prism

投稿2022/05/15 09:42

編集2023/07/30 08:22
TN8001

総合スコア9321

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

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

hiro.a

2022/05/15 11:26

回答ありがとうございます。 動きました。何が原因か考えてみます。 まずは、return _okButton ??= new MyCommandの部分ですね。 null合体演算子にして_okButtonがnullか確認してから処理をするこちらの方が無駄がないですね。 IICommandにつきましては既存のものを使います。(特に理由はないです。代わりの物をみていないので) INotifyPropertyChangedつきましては他の方は紹介していた物を使用する様にします。 (個人的にわかりやすいかったので) Text = new TestText { PutText = "hoge" };で今回は"hoge"と文字列を指定しましたが 実際はリストなどの選択されている値を取得してその値を与える予定です。 そのためExecuteのparameterはnullでも問題ないですね。(CommandParameterは特に必要としないので。) SetPropertyに関しては存在自体は知っておりました。 以前プロパティの変更通知はSetPropertyを使用しており、ご回答通りセッターで使用をしていましたが、現在使用している方法を試して使用をやめました。 あまりコードを増やしたくないがためです。 // プロパティからOnPropertyChangedを呼びやすくするヘルパ と書かれていますが、なくても問題はないと考えていますが合っていますでしょうか? また、Prismも検討しましたが今回は無しにしました。
TN8001

2022/05/15 13:49

> null合体演算子にして_okButtonがnullか確認してから処理をするこちらの方が無駄がないですね。 無駄がないというか初回だけ初期化するというテクニックですが、間違えちゃう(可能性がある)ならコンストラクタに書いたほうがいいと思います。 > 以前プロパティの変更通知はSetPropertyを使用しており、ご回答通りセッターで使用をしていましたが、現在使用している方法を試して使用をやめました。 変更通知したいプロパティが1個(あるいは少数)なら、セッターでOnPropertyChangedを呼ぶのもありだと思います。 しかしコマンド内で呼ぶのはかなり違和感があります。 > // プロパティからOnPropertyChangedを呼びやすくするヘルパ > と書かれていますが、なくても問題はないと考えていますが合っていますでしょうか? もちろん楽にするためのものなので、PropertyChangedを自分で呼ぶなら不要です(そういう意味ではOnPropertyChangedも不要です)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問