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

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

新規登録して質問してみよう
ただいま回答率
87.20%
MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

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

解決済

ItemsControlで配置したボタンが動作しない

shubk
shubk

総合スコア10

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

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

3回答

0評価

1クリップ

267閲覧

投稿2022/05/06 10:33

WPF初学者です。

wpf(MVVM)のItemsControlを使って、動的にボタンを配置しましたが、そのボタンをクリックしても動作しません。
機能の概要は以下となります。
・MVVMで作成しています。
・ボタンクリックの動作はXAML上の「Command」から呼び出しています。
・RelayCommandクラスを作成しています。
・名前と年齢のみのモデルを3人分ItemsControlで表示しており、各Item毎にボタンを1つ配置しています。
・ボタンの動作は全て同じで、固定文のメッセージボックスを表示するだけです。

トップのGrid直下などに問題のボタンを配置すると、メッセージボックスが正常に出ますが、
ItemsControl配下に配置したボタンはメッセージボックスが出力されませんでした。
デバッグしたところ、ItemsControl配下に配置したボタンをクリックしても「RelayCommand」クラスの「Execute」メソッドが呼び出されないところまでは
分かったのですがなぜ呼び出されないまで分かりませんでした。

上記原因及び対応方法、もしくは調べるためのヒントだけでも構いませんので、ご教示の程宜しくお願い致します。
ソースコードは以下となります。

View(Xaml)

<Window x:Class="WpfApp1.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <ItemsControl ItemsSource="{Binding TestList}"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Name}"></TextBlock> <TextBlock Text="{Binding Age}"></TextBlock> <Button Content="test" Height="30" Width="90" HorizontalAlignment="Left" Command="{Binding ClickOutMsg}"></Button> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid> </Window>

View(クラス)

using System.Windows; using WpfApp1.ViewModels; namespace WpfApp1.Views { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MainViewModel(); } } }

ViewModel

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.ComponentModel; using System.Windows.Input; using System.Collections.ObjectModel; using WpfApp1.Models; using System.Data; using System.Windows; using WpfApp1.Common; namespace WpfApp1.ViewModels { public class MainViewModel: INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } public ObservableCollection<Person> TestList { get; set; } public ICommand ClickOutMsg { get; set; } public MainViewModel() { ClickOutMsg = new RelayCommand(OutMsg); TestList = new ObservableCollection<Person>(Enumerable.Range(0, 3).Select(x => new Person() { Name = "tanaka" + x.ToString(), Age = (30 + x) % 50 }).ToArray()); } private void OutMsg() { MessageBox.Show("test"); } } }

Model

namespace WpfApp1.Models { public class Person { public string Name { get; set; } public int Age { get; set; } } }

RelayCommand

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace WpfApp1.Common { /// <summary> /// その機能を中継することのみを目的とするコマンド /// デリゲートを呼び出すことにより、他のオブジェクトに対して呼び出します。 ///CanExecute メソッドの既定の戻り値は 'true' です。 /// <see cref="RaiseCanExecuteChanged"/> は、次の場合は必ず呼び出す必要があります。 /// <see cref="CanExecute"/> は、別の値を返すことが予期されます。 /// </summary> public class RelayCommand : ICommand { private readonly Action _execute; private readonly Func<bool> _canExecute; /// <summary> /// RaiseCanExecuteChanged が呼び出されたときに生成されます。 /// </summary> public event EventHandler CanExecuteChanged; /// <summary> /// 常に実行可能な新しいコマンドを作成します。 /// </summary> /// <param name="execute">実行ロジック。</param> public RelayCommand(Action execute) : this(execute, null) { } /// <summary> /// 新しいコマンドを作成します。 /// </summary> /// <param name="execute">実行ロジック。</param> /// <param name="canExecute">実行ステータス ロジック。</param> public RelayCommand(Action execute, Func<bool> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } /// <summary> /// 現在の状態でこの <see cref="RelayCommand"/> が実行できるかどうかを判定します。 /// </summary> /// <param name="parameter"> /// コマンドによって使用されるデータ。コマンドが、データの引き渡しを必要としない場合、このオブジェクトを null に設定できます。 /// </param> /// <returns>このコマンドが実行可能な場合は true、それ以外の場合は false。</returns> public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(); } /// <summary> /// 現在のコマンド ターゲットに対して <see cref="RelayCommand"/> を実行します。 /// </summary> /// <param name="parameter"> /// コマンドによって使用されるデータ。コマンドが、データの引き渡しを必要としない場合、このオブジェクトを null に設定できます。 /// </param> public void Execute(object parameter) { _execute(); } /// <summary> /// <see cref="CanExecuteChanged"/> イベントを発生させるために使用されるメソッド /// <see cref="CanExecute"/> の戻り値を表すために /// メソッドが変更されました。 /// </summary> public void RaiseCanExecuteChanged() { var handler = CanExecuteChanged; if (handler != null) { handler(this, EventArgs.Empty); } } } /// <summary> /// 任意の型の引数を1つ受け付けるRelayCommand /// </summary> /// <typeparam name="T"></typeparam> public class RelayCommand<T> : ICommand { private readonly Action<T> _execute; private readonly Func<T, bool> _canExecute; /// <summary> /// RaiseCanExecuteChanged が呼び出されたときに生成されます。 /// </summary> public event EventHandler CanExecuteChanged; /// <summary> /// 常に実行可能な新しいコマンドを作成します。 /// </summary> /// <param name="execute">実行ロジック。</param> public RelayCommand(Action<T> execute) : this(execute, null) { } /// <summary> /// 新しいコマンドを作成します。 /// </summary> /// <param name="execute">実行ロジック。</param> /// <param name="canExecute">実行ステータス ロジック。</param> public RelayCommand(Action<T> execute, Func<T, bool> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } /// <summary> /// 現在の状態でこの <see cref="RelayCommand"/> が実行できるかどうかを判定します。 /// </summary> /// <param name="parameter"> /// コマンドによって使用されるデータ。コマンドが、データの引き渡しを必要としない場合、このオブジェクトを null に設定できます。 /// </param> /// <returns>このコマンドが実行可能な場合は true、それ以外の場合は false。</returns> public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute((T)parameter); } /// <summary> /// 現在のコマンド ターゲットに対して <see cref="RelayCommand"/> を実行します。 /// </summary> /// <param name="parameter"> /// コマンドによって使用されるデータ。コマンドが、データの引き渡しを必要としない場合、このオブジェクトを null に設定できます。 /// </param> public void Execute(object parameter) { _execute((T)parameter); } /// <summary> /// <see cref="CanExecuteChanged"/> イベントを発生させるために使用されるメソッド /// <see cref="CanExecute"/> の戻り値を表すために /// メソッドが変更されました。 /// </summary> public void RaiseCanExecuteChanged() { var handler = CanExecuteChanged; if (handler != null) { handler(this, EventArgs.Empty); } } } }

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

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