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.