ListView WPF: allegare un evento di doppio clic (su un elemento)


85

Ho il seguente 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>

Come posso allegare un evento a ogni elemento associato che si attiverà facendo doppio clic sull'elemento?

Risposte:


102

Ho trovato la soluzione da qui: 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 non è necessario riutilizzare lo stile, è possibile inserirlo direttamente nella sezione <ListView.Resources /> e rimuovere x: Key.
— David Schmitt,

8
Questo ha funzionato anche per me. Grazie! BTW, probabilmente vorrai interrompere il bubbling dell'evento doubleClick all'interno del tuo gestore impostando: e.Handled = true;
— Tom A

1
Ho un problema con questo. Cioè, io uso x: stili senza chiave nella finestra per definire lo stile di tutti gli elementi dell'interfaccia utente, inclusi i ListView utilizzati in un controllo personalizzato su quella finestra. Mettendo questo gestore di eventi nel xaml del controllo personalizzato si disabilita lo stile applicato nella finestra.
— Jeno Csupor

8
Solo per curiosità, c'è un altro modo per farlo che non violi MVVM?
— Dave

13
Come avvertimento: l'uso di un EventSetterpuò portare a perdite di memoria se l'obiettivo del suo gestore vive più a lungo del ListViewItem. Ho passato gli ultimi giorni a eseguire il debug di una grave perdita di memoria (20 MB alla volta), solo per scoprire che se ListViewItemla memoria associata erano trapelate attraverso un file EventSetter.
— Zach Johnson,

73

Nessuna perdita di memoria (non è necessario annullare l'iscrizione a ciascun elemento) , funziona bene:

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
Eccellente, non c'è più bisogno di preoccuparsi delle perdite di memoria e, francamente, è solo molto più pulito.
— ean5533

3
Questo non è sufficiente se la tua lista contiene un oggetto complesso. È necessario utilizzare un visual tree helper per trovare il ListViewItem genitore e da lì è possibile prendere il datacontext
— ravyoli

3
Pulito e semplice. Grazie.
— Eternal21

1
Molto gentile e disponibile. Nel mio caso ho il pulsante di selezione aggiuntivo che esegue l'azione di selezione. Quindi ho usato il doppio clic come segue: 'MouseDoubleClick = "SelectBtn_Click"' 'private void SelectBtn_Click (object sender, RoutedEventArgs e) {}'
— Kishore

3
Questo è il motivo per cui scorri sempre oltre la risposta accettata. Nel caso in cui ...
— aggsol

7

La mia soluzione era basata sulla risposta di @ epox_sub che dovresti cercare per sapere dove inserire il gestore eventi nel XAML. Il code-behind non ha funzionato per me perché i miei ListViewItemssono oggetti complessi. La risposta di @ sipwiz è stata un ottimo suggerimento su dove cercare ...

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

Il vantaggio con questo è che ottieni l' SelectedItemassociazione DataContext di ( Trackin questo caso). L'elemento selezionato funziona perché il primo clic del doppio clic lo seleziona.


4

Per coloro che sono interessati principalmente a mantenere il pattern MVVM, ho usato la risposta di Andreas Grech per fare una soluzione.

Flusso di base:

L'utente fa doppio clic sull'elemento -> Gestore eventi nel codice sottostante -> ICommand nel modello di visualizzazione

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 può essere trovato qui .

Nel mio caso, ho una raccolta di Projectoggetti che popolano il file ListView. Questi oggetti contengono più proprietà di quelle mostrate nell'elenco e apro un ProjectDetailView(a WPFWindow ) per visualizzarli.

L' senderoggetto del gestore eventi è il selected ListViewItem. Successivamente, l' Projectelemento a cui desidero accedere è contenuto all'interno della Contentproprietà.


3

Nel tuo esempio stai cercando di catturare quando viene selezionato un elemento nel tuo ListView o quando viene fatto clic su un'intestazione di colonna? Se è il primo, aggiungerai un gestore SelectionChanged.

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

In quest'ultimo caso, dovresti usare una combinazione di eventi MouseLeftButtonUp o MouseLeftButtonDown sugli elementi GridViewColumn per rilevare un doppio clic e intraprendere l'azione appropriata. In alternativa puoi gestire gli eventi su GridView e capire da lì quale intestazione di colonna era sotto il mouse.


Volevo un evento sugli oggetti delimitati, non sulle intestazioni
— Andreas Grech

È nuovo per me. Grazie per aver fornito la tua risposta (e rimuoverò la dichiarazione di assenza di evento DoubleClick dalla mia).
— Aaron Clauson

3

L'alternativa che ho usato è 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

Sulla risposta di epox_spb , ho aggiunto in un controllo per evitare errori quando si fa doppio clic in intestazioni 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!");
    }
}

molto interessante - funziona con 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; } })--- Il casting non è richiesto ma aiuta in ISE a ottenere il completamento
— BananaAcid
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.