トップ > Tech > CSharp > WPF > ListBoxのダブルクリックイベントをうまく処理する

ListBoxのダブルクリックイベントをうまく処理する

WPF の ListBox に MouseDoubleClick があるので、これにイベントハンドラをひもづけてやればダブルクリックイベントを処理できる。しかし、アイテムがダブルクリックされたかどうかはわからないし、どのアイテムがダブルクリックされたのかもすぐにはわからない。

アイテムのダブルクリックイベントだけでいい場合

そんなときは ListBox の MouseDoubleClick にはイベントハンドラを設定せず、ListBoxItem の MouseDoubleClick に Style を使って設定してやればいい。

<Style x:Key="xxx" TargetType="ListBoxItem">
    <EventSetter Event="MouseDoubleClick" Handler="listBoxItem_MouseDoubleClick"/>
</Style>

このイベントハンドラの中には sender として ListBoxItem が入ってくるので、それを利用してアイテムの特定ができる。

private void listBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var listBoxItem = sender as ListBoxItem;
    // ほげほげ
}

アイテム以外の部分でも処理するには

前項の方法では、アイテムごとの処理は可能だが、空白部分(ListBox 中のアイテムでない部分)をダブルクリックしたときにイベントが発生しない。これは ListBox の MouseDoubleClick にイベントハンドラを設定すればよさそうだが、そう単純でもない。

なぜなら、ListBoxItem と ListBox 両方の MouseDoubleClick を設定した場合、その両方が順番に呼び出されてしまうからだ。ふつうアイテム上でクリックしたときは空白部分の処理をしてほしくないはずだ。そしてこれは e.Handled = true; を設定しても関係ない。

これを回避するには ListBoxItem には MouseDoubleClick を設定しないでおく。そして、ListBox の MouseDoubleClick を定義し、その中で条件分岐させる。

具体的なコードは下記のようになる。

private void listBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    // 選択中のアイテムの ListBoxItem を取得
    var listBoxItem = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
    // ヒットテストでアイテム上
    if (listBoxItem.InputHitTest(e.GetPosition(listBoxItem)) != null)
    {
        // 選択中のアイテム上でダブルクリックされたとき
    }
    else
    {
        // アイテム以外でダブルクリックされたとき
    }
}

ダブルクリックした時点でそのアイテムが選択されていることが前提となっている。そうでない場合は、改良が必要だ。

まず、選択されているアイテム(listBox.SelectedItem)からそのコンテナの ListBoxItem を割り出す。そして、そのアイテム上でダブルクリックされたポイント(e.GetPosition(listBoxItem))のヒットテストを行う(InputHitTest)。

これによってアイテム上でクリックされた場合はなんらかの UIElement が返ってくるし、それ以外の場合は null が返る。あとはこれに従って条件式を書けばよい。

スマートではないが、とりあえずこれでなんとかなったので、よしとする。

(2010/09/22 17:07:58)
27423
プロフィール

Kenz Yamada(山田研二)。1984年生。大阪。ちょっとずつ好きなプログラム作ってます。 好きなものはカメラと旅行。ガジェットや身の回り、ちょっとこだわります。 詳しくは Web mixi で。

Bookmark and Share