かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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の任意の項目をダブルクリックしてみると、ちゃんとメッセージボックスが表示されます!!ばっちり。