かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ListBoxの項目がダブルクリックされたらViewModelのCommand(or メソッド)を呼ぶ

タイトルの通りのことを、コードビハインド無しでやろうとしたら・・・?ということでやってみました。
ViewModelやModel側はこんな感じ。今回は、VMにうまいこと処理がわたったのがわかるように、VMでMessageBox出してます。ご愛嬌ということで。

namespace ListBoxItemTest
{
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Windows;

    public class MainWindowViewModel
    {
        public ObservableCollection<Person> People { get; private set; }

        public MainWindowViewModel()
        {
            // ダミーデータ
            this.People = new ObservableCollection<Person>(
                Enumerable.Range(1, 100).Select(i => new Person { Name = "田中 太郎" + i }));
        }

        // 選択中の人
        public Person SelectedPerson { get; set; }

        // ListBoxのアイテムをダブルクリックされたら呼ばれるメソッド
        public void Execute()
        {
            // とりあえず呼ばれたことがわかるようにVMでメッセージボックス出してます。
            // 本当は、VMでこんなことしたらダメよ!
            if (this.SelectedPerson == null)
            {
                MessageBox.Show("NULL");
                return;
            }
            MessageBox.Show(this.SelectedPerson.Name);
        }
    }

    // ListBoxに表示するデータ
    public class Person
    {
        public string Name { get; set; }
    }
}

View側

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:ListBoxItemTest"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
        x:Class="ListBoxItemTest.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <l:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <!-- HorizontalContentAlignmentでListBoxの項目を横いっぱいに広げる。
             これをしないとダブルクリックに反応しないエリアが出来ちゃう-->
        <ListBox x:Name="listBox1" 
                 ItemsSource="{Binding People}" 
                 SelectedItem="{Binding SelectedPerson}" 
                 HorizontalContentAlignment="Stretch">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <ContentControl Content="{Binding Name}">
                    	<i:Interaction.Triggers>
                    		<i:EventTrigger EventName="MouseDoubleClick">
                    			<!-- RelativeSourceで何処まで遡るかで任意のVMのメソッドが呼べる。
                                     ListBoxItemまでならPersonオブジェクト。ListBoxまで遡るとMainWindowViewModel。
                                    あと、コマンド作るのがだるかったのでCallMethodActionでちょっと手抜き -->
                                <ei:CallMethodAction 
                                    TargetObject="{Binding Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=DataContext}" 
                                    MethodName="Execute"/>
                    		</i:EventTrigger>
                    	</i:Interaction.Triggers>
                    </ContentControl>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

実行して、ListBoxの任意の項目をダブルクリックしてみると、ちゃんとメッセージボックスが表示されます!!ばっちり。