Eu descobri uma maneira muito fácil e limpa de fazer isso com os gatilhos de eventos do Blend SDK. MVVM limpo, reutilizável e sem code-behind.
Você provavelmente já tem algo assim:
<Style x:Key="MyListStyle" TargetType="{x:Type ListViewItem}">
Agora inclua um ControlTemplate para ListViewItem como este se você ainda não usa um:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}" />
</ControlTemplate>
</Setter.Value>
</Setter>
O GridViewRowPresenter será a raiz visual de todos os elementos "internos" que constituem um elemento de linha da lista. Agora poderíamos inserir um gatilho lá para procurar eventos roteados MouseDoubleClick e chamar um comando por meio de InvokeCommandAction como este:
<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>
Se você tiver elementos visuais "acima" do GridRowPresenter (provavelmente começando com uma grade), você também pode colocar o Trigger lá.
Infelizmente, os eventos MouseDoubleClick não são gerados a partir de todos os elementos visuais (eles são de Controls, mas não de FrameworkElements, por exemplo). Uma solução alternativa é derivar uma classe de EventTrigger e procurar MouseButtonEventArgs com ClickCount de 2. Isso filtra efetivamente todos os não-MouseButtonEvents e todos os MoseButtonEvents com 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);
}
}
}
Agora podemos escrever isso ('h' é o namespace da classe auxiliar acima):
<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>