WPF ListView: Anexando um evento de clique duplo (em um item)


85

Eu tenho o seguinte ListView:

<ListView Name="TrackListView">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Title" Width="100" 
                            HeaderTemplate="{StaticResource BlueHeader}" 
                            DisplayMemberBinding="{Binding Name}"/>

            <GridViewColumn Header="Artist" Width="100"  
                            HeaderTemplate="{StaticResource BlueHeader}"  
                            DisplayMemberBinding="{Binding Album.Artist.Name}" />
        </GridView>
    </ListView.View>
</ListView>

Como posso anexar um evento a cada item vinculado que será disparado ao clicar duas vezes no item?

Respostas:


102

Encontrei a solução aqui: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/3d0eaa54-09a9-4c51-8677-8e90577e7bac/


XAML:

<UserControl.Resources>
    <Style x:Key="itemstyle" TargetType="{x:Type ListViewItem}">
        <EventSetter Event="MouseDoubleClick" Handler="HandleDoubleClick" />
    </Style>
</UserControl.Resources>

<ListView Name="TrackListView" ItemContainerStyle="{StaticResource itemstyle}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Title" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Name}"/>
            <GridViewColumn Header="Artist" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Artist.Name}" />
        </GridView>
    </ListView.View>
</ListView>

C #:

protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
{
    var track = ((ListViewItem) sender).Content as Track; //Casting back to the binded Track
}

14
Se você não precisar reutilizar o estilo, pode colocá-lo diretamente na seção <ListView.Resources /> e remover o x: Key.
— David Schmitt

8
Isso funcionou para mim também. Obrigado! BTW, você provavelmente desejará parar o borbulhar do evento doubleClick em seu manipulador definindo: e.Handled = true;
— Tom A

1
Eu tenho um problema com isto. Ou seja, eu uso estilos sem chave x: na janela para definir o estilo de todos os elementos da interface do usuário, incluindo ListViews usados ​​em um controle personalizado nessa janela. Colocar este manipulador de eventos no xaml do controle personalizado desativa o estilo aplicado na janela.
— Jeno Csupor

8
Só por curiosidade, existe outra maneira de fazer isso que não viole o MVVM?
— Dave

13
Como um aviso: o uso de um EventSetterpode causar vazamentos de memória se o destino de seu manipulador viver mais do que o ListViewItem. Passei os últimos dias depurando um sério vazamento de memória (20 MB por vez), apenas para descobrir que se ListViewItema memória associada estava vazando por meio de um EventSetter.
— Zach Johnson

73

Sem vazamentos de memória (não há necessidade de cancelar a assinatura de cada item) , funciona bem:

XAML:

<ListView MouseDoubleClick="ListView_MouseDoubleClick" ItemsSource="{Binding TrackCollection}" />

C #:

    void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var item = ((FrameworkElement) e.OriginalSource).DataContext as Track;
        if (item != null)
        {
            MessageBox.Show("Item's Double Click handled!");
        }
    }

1
Excelente, não há mais necessidade de se preocupar com vazamentos de memória e, francamente, é muito mais limpo.
— ean5533

3
Isso não é suficiente se sua lista contiver um objeto complexo. Você precisa usar um auxiliar de árvore visual para encontrar o ListViewItem pai e de lá você pode pegar o datacontext
— ravyoli

3
Limpo e simples. Obrigado.
— Eternal21

1
Muito bom e útil. No meu caso, tenho o botão de seleção adicional que executa a ação de seleção. Então, usei o duplo clique da seguinte forma: 'MouseDoubleClick = "SelectBtn_Click"' 'private void SelectBtn_Click (object sender, RoutedEventArgs e) {}'
— Kishore

3
É por isso que você sempre passa pela resposta aceita. Apenas no caso ...
— aggsol

7

Minha solução foi baseada na resposta de @epox_sub, que você deve examinar para saber onde colocar o Event Handler no XAML. O code-behind não funcionou para mim porque ListViewItemssão objetos complexos. A resposta de @sipwiz foi uma ótima dica de onde procurar ...

void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var item = ListView.SelectedItem as Track;
    if (item != null)
    {
      MessageBox.Show(item + " Double Click handled!");
    }
}

O bônus com isso é que você obtém a SelectedItemvinculação DataContext do ( Trackneste caso). Item selecionado funciona porque o primeiro clique do clique duplo o seleciona.


4

Para aqueles interessados ​​principalmente em manter o padrão MVVM, usei a resposta de Andreas Grech para fazer uma solução alternativa .

Fluxo básico:

O usuário clica duas vezes no item -> manipulador de eventos no code behind -> ICommand no modelo de visualização

ProjectView.xaml:

<UserControl.Resources>
    <Style TargetType="ListViewItem" x:Key="listViewDoubleClick">
        <EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick"/>
    </Style>
</UserControl.Resources>

...

<ListView ItemsSource="{Binding Projects}" 
          ItemContainerStyle="{StaticResource listViewDoubleClick}"/>

ProjectView.xaml.cs:

public partial class ProjectView : UserControl
{
    public ProjectView()
    {
        InitializeComponent();
    }

    private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        ((ProjectViewModel)DataContext)
            .ProjectClick.Execute(((ListViewItem)sender).Content);
    }
}

ProjectViewModel.cs:

public class ProjectViewModel
{
    public ObservableCollection<Project> Projects { get; set; } = 
               new ObservableCollection<Project>();

    public ProjectViewModel()
    {
        //Add items to Projects
    }

    public ICommand ProjectClick
    {
        get { return new DelegateCommand(new Action<object>(OpenProjectInfo)); }
    }

    private void OpenProjectInfo(object _project)
    {
        ProjectDetailView project = new ProjectDetailView((Project)_project);
        project.ShowDialog();
    }
}

DelegateCommand.cs pode ser encontrado aqui .

No meu caso, tenho uma coleção de Projectobjetos que povoam o ListView. Esses objetos contêm mais propriedades do que as mostradas na lista e abro um ProjectDetailView(um WPF Window) para exibi-los.

O senderobjeto do manipulador de eventos é o selecionado ListViewItem. Posteriormente, o Projectque desejo acessar está contido na Contentpropriedade.


3

Em seu exemplo, você está tentando capturar quando um item em seu ListView é selecionado ou quando um cabeçalho de coluna é clicado? Se for o primeiro, você adicionaria um manipulador SelectionChanged.

<ListView Name="TrackListView" SelectionChanged="MySelectionChanged">

Se for o último, você terá que usar alguma combinação de eventos MouseLeftButtonUp ou MouseLeftButtonDown nos itens GridViewColumn para detectar um clique duplo e executar a ação apropriada. Alternativamente, você pode manipular os eventos no GridView e descobrir a partir daí qual cabeçalho da coluna está sob o mouse.


Eu queria um evento sobre os itens delimitados, não os cabeçalhos
— Andreas Grech,

Isso é novo para mim. Obrigado por colocar sua resposta (e vou remover a declaração de nenhum evento da DoubleClick da minha).
— Aaron Clauson,

3

A alternativa que usei é Event To Command,

<ListView ItemsSource="{Binding SelectedTrack}" SelectedItem="{Binding SelectedTrack}" >
    <i:Interaction.Triggers>
         <i:EventTrigger EventName="MouseDoubleClick">
              <i:InvokeCommandAction Command="{Binding SelectTrackCommand}"/>
         </i:EventTrigger>
    </i:Interaction.Triggers>
    ...........
    ...........
</ListView>

1

Com base na resposta de epox_spb , adicionei uma verificação para evitar erros ao clicar duas vezes nos cabeçalhos GridViewColumn.

void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var dataContext = ((FrameworkElement)e.OriginalSource).DataContext;
    if (dataContext is Track)
    {
        MessageBox.Show("Item's Double Click handled!");
    }
}

muito legal - funciona com PowerShell- $myListView.Add_MouseDoubleClick({ Param($sender, $ev); $e = [System.Windows.Input.MouseButtonEventArgs]$ev; $itemData = ([System.Windows.FrameworkElement]$e.OriginalSource).DataContext }); if ($item -ne $null) { Write-Host $itemData; } })--- A fundição não é necessária, mas ajuda no ISE a obter a conclusão
— BananaAcid
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.