WPF ListView: присоединение события двойного щелчка (по элементу)

85

Имею следующее 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>

Как я могу привязать событие к каждому связанному элементу, которое срабатывает при двойном щелчке по элементу?

Андреас Греч
источник

Ответы:

102

Нашел решение здесь: 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
}
Андреас Греч
источник
13
Если вам не нужно повторно использовать стиль, вы можете поместить его прямо в раздел <ListView.Resources /> и удалить ключ x: Key.
Дэвид Шмитт
8
У меня это тоже сработало. Благодарность! Кстати, вы, вероятно, захотите остановить всплытие события doubleClick в своем обработчике, установив: e.Handled = true;
Tom A
1
У меня с этим проблема. То есть я использую стили x: Key -less в окне для стилизации всех элементов пользовательского интерфейса, включая ListViews, используемые в настраиваемом элементе управления в этом окне. Помещение этого обработчика событий в xaml настраиваемого элемента управления отключает стиль, примененный в окне.
Jeno Csupor 02
8
Просто из любопытства, есть ли другой способ сделать это, не нарушающий MVVM?
Дэйв
13
В качестве предупреждения: использование EventSetterможет привести к утечке памяти, если цель его обработчика живет дольше, чем ListViewItem. Я потратил последние несколько дней на отладку серьезной утечки памяти (20 МБ за раз) только для того, чтобы обнаружить, что ListViewItems и связанная с ними память утекают через файл EventSetter.
Зак Джонсон,
70

Никаких утечек памяти (не нужно отписываться по каждому пункту) , работает нормально:

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!");
        }
    }
эпоксидная смола
источник
1
Отлично, больше не нужно беспокоиться об утечках памяти, и, честно говоря, это намного чище.
ean5533
3
Этого недостаточно, если ваш список содержит сложный объект. Вам нужно использовать помощник по визуальному дереву, чтобы найти родительский ListViewItem, и оттуда вы можете взять
текст данных
3
Чисто и просто. Спасибо.
Eternal21
1
Очень приятно и полезно. В моем случае у меня есть дополнительная кнопка выбора, которая выполняет действие выбора. Поэтому я использовал двойной щелчок следующим образом: 'MouseDoubleClick = "SelectBtn_Click"' 'private void SelectBtn_Click (object sender, RoutedEventArgs e) {}'
Кишор,
3
Вот почему вы всегда прокручиваете принятый ответ. На всякий случай ...
aggsol 05
7

Мое решение было основано на ответе @ epox_sub, на который вы должны посмотреть, где разместить обработчик событий в XAML. Код программной части у меня не работал, потому что мои ListViewItemsобъекты сложны. Ответ @sipwiz был отличным намеком на то, где искать ...

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

Бонус в том, что вы получаете SelectedItemпривязку DataContext ( Trackв данном случае). Выбранный элемент работает, потому что его выбирает первый щелчок двойного щелчка.

CAD парень
источник
4

Для тех, кто в основном заинтересован в поддержке шаблона MVVM, я использовал ответ Андреаса Греча, чтобы обойти его.

Основной поток:

Пользователь дважды щелкает элемент -> Обработчик событий в коде позади -> ICommand в модели представления

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 можно найти здесь .

В моем случае у меня есть коллекция Projectобъектов, которые заполняют ListView. Эти объекты содержат больше свойств, чем показано в списке, и я открываюProjectDetailView (WPF Window), чтобы отобразить их.

senderОбъект обработчика события является выбранным ListViewItem. Впоследствии то, к Projectчему я хочу получить доступ, содержится в Contentсвойстве.

Мика Верталь
источник
3

В вашем примере вы пытаетесь поймать, когда выбран элемент в вашем ListView или когда нажимается заголовок столбца? Если это первое, вы должны добавить обработчик SelectionChanged.

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

В последнем случае вам придется использовать некоторую комбинацию событий MouseLeftButtonUp или MouseLeftButtonDown для элементов GridViewColumn, чтобы обнаружить двойной щелчок и предпринять соответствующие действия. В качестве альтернативы вы можете обрабатывать события в GridView и определять оттуда, какой заголовок столбца был под курсором мыши.

Аарон Клаусон
источник
Я хотел, чтобы событие касалось связанных элементов, а не заголовков
Андреас Греч
Для меня это ново. Спасибо, что разместили свой ответ (и я удалю из своей инструкции no DoubleClick).
Аарон Клаусон
3

Альтернативой, которую я использовал, является 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

Основываясь на ответе epox_spb , я добавил проверку, чтобы избежать ошибок при двойном щелчке по заголовкам 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!");
    }
}
Kramer
источник
очень круто - работает с 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; } })--- Приведение не требуется, но помогает в ISE получить завершение
BananaAcid