その9:http://blogs.wankuma.com/kazuki/archive/2008/03/24/129257.aspx
ということで、データバインディングと共にコマンドを使ってみようと思う。
唐突かもしれないけど、ICommandSourceを実装するクラスには大体CommandParameterとかいうプロパティが定義されてる。
それは、多くのクラスで依存プロパティとして定義されている!ということはバインドすることが出来る。List系のバインドと組み合わせると、選択してる要素に対して何かをやるとかいったことがすっきり書けそうな気がする。
ということで早速実験。
まずは、Personクラスと今回使うコマンドを定義する。
using System.Windows.Input;
namespace WpfCommand10
{
public static class SampleCommands
{
public static readonly RoutedUICommand Detail = new RoutedUICommand(
"詳細表示", "Detail", typeof(SampleCommands));
}
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
}
そして、Window1.xaml.csのDataContextに、Personの配列をつっこんでおく。
public Window1()
{
InitializeComponent();
DataContext = new[] {
new Person { ID = 0, Name = "田中 太郎", Age = 54, Address = "東京都のどっか1" },
new Person { ID = 1, Name = "2中 2郎", Age = 10, Address = "東京都のどっか2" },
new Person { ID = 2, Name = "3中 3郎", Age = 3, Address = "東京都のどっか3" },
new Person { ID = 3, Name = "4中 4郎", Age = 1, Address = "東京都のどっか4" },
};
}
この勢いで画面もさくっと作る!!
画面的には詳細ボタンの乗ったToolBarが上部にあって、下部にGrid形式のListViewがいる。
ListViewにはIDと名前と年齢を表示しておいて、詳細ボタンを押したときに、メッセージボックスに住所まで含めた情報を表示する。
<Window x:Class="WpfCommand10.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfCommand10="clr-namespace:WpfCommand10"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
<!-- 詳細表示コマンドをバインド -->
<CommandBinding
Command="{x:Static WpfCommand10:SampleCommands.Detail}"
Executed="DetailCommandBinding_Executed"
CanExecute="DetailCommandBinding_CanExecute" />
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ToolBarTray>
<ToolBar>
<Button Content="詳細"
Command="{x:Static WpfCommand10:SampleCommands.Detail}"
CommandParameter="{Binding Path=CurrentItem}"/> <!-- CurrentItemで現在行!! -->
</ToolBar>
</ToolBarTray>
<ListView Grid.Row="1" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="名前" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="年齢" DisplayMemberBinding="{Binding Age}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
さくっとのつもりが結構時間かかってしまった。
リストをListViewにバインドするのは楽勝だったけど、ボタンのCommandParameterに現在選択されているオブジェクトを指定する方法がわからなかった。
結局のところ、このときのBindingのSourceはICollectionViewなのでCurrentItemプロパティをPathに指定してやればよかった。
ふぅ。勉強になった。
後は、CanExecuteとExecutedイベントを書いて完成。
using System.Windows;
using System.Windows.Input;
namespace WpfCommand10
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new[] {
new Person { ID = 0, Name = "田中 太郎", Age = 54, Address = "東京都のどっか1" },
new Person { ID = 1, Name = "2中 2郎", Age = 10, Address = "東京都のどっか2" },
new Person { ID = 2, Name = "3中 3郎", Age = 3, Address = "東京都のどっか3" },
new Person { ID = 3, Name = "4中 4郎", Age = 1, Address = "東京都のどっか4" },
};
}
private void DetailCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
var p = e.Parameter as Person;
if (p != null)
{
MessageBox.Show(string.Format("ID:{0}, Name:{1}, Age:{2}, Address:{3}", p.ID, p.Name, p.Age, p.Address));
}
}
private void DetailCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter != null;
}
}
}
CanExecuteは、パラメータに値が入ってるかどうかをチェックする。
Executedは、パラメータがPersonだったらID Name Age Addressを文字列にしてメッセージボックスに表示している。
実行すると下のようになる。
起動直後
適当な行を選んで詳細をクリック
ということで、バインドとコマンドを組み合わせればマスター詳細系のときにすっきりできそうな気がした。
以上!