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
}

14
Якщо вам не потрібно повторно використовувати стиль, ви можете помістити його безпосередньо в розділ <ListView.Resources /> і видалити ключ x:.
Девід Шмітт,

8
Це спрацювало і на мене. Дякую! До речі, ви, мабуть, захочете зупинити бульбашку події doubleClick у вашому обробнику, встановивши: e.Handled = true;
Tom A

1
У мене проблема з цим. Тобто, я використовую стилі x: без ключів у вікні, щоб стилізувати всі елементи інтерфейсу, включаючи ListViews, що використовуються в користувацькому елементі керування у цьому вікні. Поміщення цього обробника подій у спеціальний елемент керування xaml відключає стиль, застосований у вікні.
Jeno Csupor

8
Просто з цікавості, чи є інший спосіб зробити це, який не порушує MVVM?
Дейв

13
Як попередження: використання файлу EventSetterможе призвести до витоків пам'яті, якщо ціль його обробника живе довше, ніж ListViewItem. Я витратив останні кілька днів, налагоджуючи серйозний витік пам'яті (20 Мб за раз), лише щоб з'ясувати, що ListViewItems та пов'язана з ними пам'ять просочується через EventSetter.
Зак Джонсон,

71

Відсутність витоків пам’яті (не потрібно відписувати кожен пункт) , працює нормально:

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
Чудово, більше не потрібно турбуватися про витоки пам’яті, і, чесно кажучи, це просто напевно чистіше.
ean5533

3
Цього недостатньо, якщо ваш список містить складний об’єкт. Вам потрібно скористатися візуальним помічником дерева, щоб знайти батьківський ListViewItem, і звідти ви можете взяти
datacontext

3
Чисто і просто. Дякую.
Eternal21,

1
Дуже приємно та корисно. У моєму випадку у мене є додаткова кнопка вибору, яка виконує дію вибору. Тож я використав подвійне клацання наступним чином: 'MouseDoubleClick = "SelectBtn_Click"' 'private void SelectBtn_Click (відправник об'єкта, RoutedEventArgs e) {}'
Kishore,

3
Ось чому ви завжди прокручуєте повз прийняту відповідь. Про всяк випадок ...
aggsol

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в даному випадку). Вибраний елемент працює, оскільки перший клік подвійного клацання виділяє його.


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 і звідти визначати, який заголовок стовпця знаходиться під мишею.


Я хотів події щодо обмежених елементів, а не заголовків
Андреас Грех,

Це нове для мене. Дякуємо, що подали свою відповідь (і я видалю заяву про відсутність події 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!");
    }
}

дуже круто - працює з 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.