web-dev-qa-db-fra.com

WPF ListView: Attacher un événement de double-clic (sur un élément)

J'ai la ListView suivante:

<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>

Comment puis-je attacher un événement à chaque élément lié qui sera déclenché en double-cliquant sur celui-ci?

78
Andreas Grech

Trouvez la solution à partir d'ici: 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
}
94
Andreas Grech

Aucune fuite de mémoire, fonctionne bien:

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!");
        }
    }
60
epox_spb

Ma solution était basée sur la réponse de @ epox_sub que vous devriez rechercher pour savoir où placer le gestionnaire d'événements dans le XAML. Le code-behind n'a pas fonctionné pour moi car mes ListViewItems sont des objets complexes. La réponse de @ sipwiz était un bon indice pour savoir où regarder ...

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

Le bonus à cela est que vous obtenez la liaison DataContext de SelectedItem (Track dans ce cas). L'élément sélectionné fonctionne parce que le premier clic du double-clic le sélectionne.

5
CAD bloke

Pour ceux qui souhaitaient principalement conserver le modèle MVVM, j'ai utilisé la réponse d'Andreas Grech pour créer une solution de contournement.

Flux de base:

L'utilisateur double-clique sur l'élément -> Gestionnaire d'événements dans le code derrière -> ICommand dans voir le modèle

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 peut être trouvé ici .

Dans mon cas, j'ai une collection d'objets Project qui remplissent la ListView. Ces objets contiennent plus de propriétés que ne le montre la liste et j'ouvre une ProjectDetailView (une WPF Window) pour les afficher.

L'objet sender du gestionnaire d'événements est la ListViewItem sélectionnée. Par la suite, la Project à laquelle je veux accéder est contenue dans la propriété Content.

3
Micah Vertal

Dans votre exemple, essayez-vous de capturer lorsqu'un élément de votre ListView est sélectionné ou lorsqu'un en-tête de colonne est cliqué? Si c'est le premier, vous ajouteriez un gestionnaire SelectionChanged.

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

Si c'est le dernier cas, vous devrez utiliser une combinaison d'événements MouseLeftButtonUp ou MouseLeftButtonDown sur les éléments GridViewColumn pour détecter un double-clic et prendre les mesures appropriées. Sinon, vous pouvez gérer les événements sur le GridView et déterminer à partir de là quel en-tête de colonne se trouvait sous la souris.

3
sipwiz

En me basant sur la réponse de epox_spb , j’ai ajouté à une vérification pour éviter les erreurs lors du double-clic dans les en-têtes 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!");
    }
}
0
Kramer