Я нашел очень простой и понятный способ сделать это с помощью триггеров событий Blend SDK. Чистый MVVM, многоразовый и без кода программной части.
У вас наверняка уже есть что-то вроде этого:
<Style x:Key="MyListStyle" TargetType="{x:Type ListViewItem}">
Теперь включите ControlTemplate для ListViewItem, как это, если вы его еще не используете:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}" />
</ControlTemplate>
</Setter.Value>
</Setter>
GridViewRowPresenter будет визуальным корнем всех элементов «внутри», составляющих элемент строки списка. Теперь мы могли бы вставить туда триггер для поиска перенаправленных событий MouseDoubleClick и вызвать команду через InvokeCommandAction следующим образом:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding DoubleClickCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</GridViewRowPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
Если у вас есть визуальные элементы «над» GridRowPresenter (возможно, начиная с сетки), вы также можете поместить туда триггер.
К сожалению, события MouseDoubleClick не генерируются для каждого визуального элемента (например, они происходят из Controls, но не из FrameworkElements). Обходной путь - создать класс из EventTrigger и искать MouseButtonEventArgs с ClickCount, равным 2. Это эффективно отфильтровывает все события, отличные от MouseButtonEvents, и все MoseButtonEvents с ClickCount! = 2.
class DoubleClickEventTrigger : EventTrigger
{
protected override void OnEvent(EventArgs eventArgs)
{
var e = eventArgs as MouseButtonEventArgs;
if (e == null)
{
return;
}
if (e.ClickCount == 2)
{
base.OnEvent(eventArgs);
}
}
}
Теперь мы можем написать это ('h' - это пространство имен вспомогательного класса выше):
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}">
<i:Interaction.Triggers>
<h:DoubleClickEventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DoubleClickCommand}" />
</h:DoubleClickEventTrigger>
</i:Interaction.Triggers>
</GridViewRowPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>