よくわすれるので自分用のメモ。
タイトルのようなことをやる場合は次のようにやります。

こういうのやりたいときって、たぶんDataGridにボタン配置してある列の値をみて処理したいみたいなやつが多いと思います。(自分がそうだった…)
でも、全部書くとめんどくさいので今回は簡単なサンプルにします。DataGridのやつは次のネタにでもします。

今回はテキストボックスに入力された文字列をボタンを押したら表示するようなサンプルにします。

イメージ1
イメージ2

たぶん一般的にDelegateCommadみたいなクラスを作ると思いますが、それをジェネリッククラスにします。
下記のような感じ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
using System.Windows.Input;

namespace sample
{
public class DelegateCommand<T> : ICommand
{

private readonly Action<T> _execute;
private readonly Func<bool> _canExecute;

public event EventHandler CanExecuteChanged;

public DelegateCommand(Action<T> execute) : this(execute, () => true) { }

public DelegateCommand(Action<T> execute, Func<bool> canExecute)
{
this._execute = execute;
this._canExecute = canExecute;
}

public void Execute(object parameter)
{
this._execute((T)parameter);
}

public bool CanExecute(object parameter)
{
return this._canExecute();
}

}
}

ViewModelにはおなじみ(?)のINotifyPropertyChangedを実装したViewModelBaseを継承します。
以下、ViewModelBaseです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Windows.Threading;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace sample
{
public class ViewModelsBase : DispatcherObject, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

ViewModelBaseを継承したViewModelを作ります。
コンストラクタでICommandに先ほどのDelegateCommandを使ったメソッドを登録します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System.Windows;
using System.Windows.Input;

namespace sample
{
public class MainWindowViewModel : ViewModelsBase
{
private string _message;
/// <summary>
/// 画面のテキストボックスとバインディング
/// </summary>
public string Message
{
get { return this._message; }
set
{
this._message = value;
this.OnPropertyChanged();
}
}

/// <summary>
/// コンストラクタ
/// </summary>
public MainWindowViewModel()
{

this.ShowMessageCommand = new DelegateCommand<string>(ShowMessage);
}

public ICommand ShowMessageCommand { get; private set; }

private void ShowMessage(string message)
{

MessageBox.Show(message);
}
}
}

最後にView。
ButtonのCommandにViewModelで記述したCommandをバインドして、CommandParameterに引数を指定します。
今回の場合だと、ViewModelのMessageプロパティをバインドしてます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<Window x:Class="sample.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:sample"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="200">

<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>

<Grid>
<StackPanel>
<TextBox Height="30" Width="80" Margin="5,5,5,5"
Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>

<Button Height="30" Width="80"
Content="表示"
Command="{Binding ShowMessageCommand}" CommandParameter="{Binding Message}"
/>

</StackPanel>
</Grid>
</Window>

以上。

次はDataGridで値の引数をつかうボタンについて書きます。
たぶん…

追記 2016/12/11

ちなみに、ViewModelBaseとかDelegateCommandとかはおとなしくPrism辺りを使った方がいいと思います。
オレオレで実装する人とかたぶんあんまりいないし、私も次回作るとしたらそうします。ただ、会社でも家でもWPFやる機会がもうなさそうですが…