WPF ListView: Anhängen eines Doppelklickereignisses (auf ein Element)

84

Ich habe folgendes 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>

Wie kann ich jedem gebundenen Element ein Ereignis hinzufügen, das beim Doppelklicken auf das Element ausgelöst wird?

Andreas Grech
quelle

Antworten:

100

Die Lösung finden Sie hier: 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
}
Andreas Grech
quelle
13
Wenn Sie den Stil nicht erneut verwenden müssen, können Sie ihn direkt in den Abschnitt <ListView.Resources /> einfügen und den x: Key entfernen.
David Schmitt
8
Das hat auch bei mir funktioniert. Vielen Dank! Übrigens möchten Sie wahrscheinlich das Sprudeln des doubleClick-Ereignisses in Ihrem Handler stoppen, indem Sie Folgendes festlegen: e.Handled = true;
Tom A
1
Ich habe ein Problem damit. Das heißt, ich verwende x: Key-less-Stile im Fenster, um alle UI-Elemente zu formatieren, einschließlich der ListViews, die in einem benutzerdefinierten Steuerelement in diesem Fenster verwendet werden. Wenn Sie diesen Ereignishandler in die xaml des benutzerdefinierten Steuerelements einfügen, wird der im Fenster angewendete Stil deaktiviert.
Jenő Csupor
8
Gibt es aus Neugier einen anderen Weg, der MVVM nicht verletzt?
Dave
13
Als Warnung: Die Verwendung von a EventSetterkann zu Speicherverlusten führen, wenn das Ziel des Handlers länger als das des ListViewItem. Ich habe die letzten Tage damit verbracht, ein schwerwiegendes Speicherleck (jeweils 20 MB) zu debuggen, nur um herauszufinden, dass ListViewItems und der zugehörige Speicher durch ein EventSetter.
Zach Johnson
69

Keine Speicherverluste (kein Abmelden jedes Elements erforderlich) , funktioniert einwandfrei:

XAML:

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

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!");
        }
    }
Epox
quelle
1
Ausgezeichnet, Sie müssen sich keine Sorgen mehr über Speicherlecks machen, und ehrlich gesagt ist es einfach verdammt sauberer.
ean5533
3
Dies reicht nicht aus, wenn Ihre Liste ein komplexes Objekt enthält. Sie müssen einen visuellen Baumhelfer verwenden, um das übergeordnete ListViewItem zu finden, und von dort können Sie den Datenkontext
Ravyoli
3
Sauber und einfach. Vielen Dank.
Eternal21
1
Sehr nett und hilfsbereit. In meinem Fall habe ich die zusätzliche Auswahlschaltfläche, die die Auswahlaktion ausführt. Also habe ich den Doppelklick wie folgt verwendet: 'MouseDoubleClick = "SelectBtn_Click"' 'private void SelectBtn_Click (Objektabsender, RoutedEventArgs e) {}'
Kishore
3
Deshalb scrollen Sie immer über die akzeptierte Antwort hinaus. Nur für den Fall ...
Aggsol
7

Meine Lösung basierte auf der Antwort von @ epox_sub, nach der Sie suchen sollten, wo der Ereignishandler in der XAML abgelegt werden soll. Der Code-Behind hat bei mir nicht funktioniert, da ListViewItemses sich um komplexe Objekte handelt. Die Antwort von @ sipwiz war ein großartiger Hinweis darauf, wo man suchen sollte ...

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

Der Bonus dabei ist, dass Sie die SelectedItemDataContext-Bindung ( Trackin diesem Fall) erhalten. Das ausgewählte Element funktioniert, da es durch den ersten Klick des Doppelklicks ausgewählt wird.

CAD-Typ
quelle
4

Für diejenigen, die hauptsächlich das MVVM-Muster beibehalten möchten, habe ich die Antwort von Andreas Grech verwendet , um eine Lösung zu finden.

Grundablauf:

Benutzer doppelklickt auf Element -> Ereignishandler im Code dahinter -> Befehl im Ansichtsmodell

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 finden Sie hier .

In meinem Fall habe ich eine Sammlung von ProjectObjekten, die das füllen ListView. Diese Objekte enthalten mehr Eigenschaften als in der Liste angezeigt, und ich öffne eine ProjectDetailView(eine WPF Window), um sie anzuzeigen.

Das senderObjekt des Ereignishandlers ist das ausgewählte ListViewItem. Anschließend ist das Project, auf das ich zugreifen möchte, in der ContentEigenschaft enthalten.

Micah Vertal
quelle
3

Versuchen Sie in Ihrem Beispiel zu erfassen, wann ein Element in Ihrer ListView ausgewählt ist oder wann auf eine Spaltenüberschrift geklickt wird? Wenn es das erstere ist, würden Sie einen SelectionChanged-Handler hinzufügen.

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

In letzterem Fall müssten Sie eine Kombination von MouseLeftButtonUp- oder MouseLeftButtonDown-Ereignissen für die GridViewColumn-Elemente verwenden, um einen Doppelklick zu erkennen und entsprechende Maßnahmen zu ergreifen. Alternativ können Sie die Ereignisse in GridView verarbeiten und von dort aus herausfinden, welche Spaltenüberschrift sich unter der Maus befand.

sipwiz
quelle
Ich wollte ein Ereignis für die begrenzten Elemente, nicht für die Überschriften
Andreas Grech
Das ist neu für mich. Vielen Dank für Ihre Antwort (und ich werde die no DoubleClick-Ereignisanweisung aus meiner entfernen).
Sipwiz
3

Alternative, die ich verwendet habe, ist 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>
Codename Jack
quelle
1

Aufbauend auf der Antwort von epox_spb habe ich eine Überprüfung hinzugefügt, um Fehler beim Doppelklicken in die GridViewColumn-Header zu vermeiden.

void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var dataContext = ((FrameworkElement)e.OriginalSource).DataContext;
    if (dataContext is Track)
    {
        MessageBox.Show("Item's Double Click handled!");
    }
}
Kramer
quelle
sehr cool - funktioniert mit 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; } })--- Casting ist nicht erforderlich, hilft aber in ISE, die Fertigstellung zu erreichen
BananaAcid