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

У меня есть следующее 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>

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

8 ответов

Решение

Нашел решение здесь: 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
}

Нет утечек памяти, отлично работает

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_sub, который вы должны найти, где поместить обработчик событий в XAML. Код позади не работал для меня, потому что мой ListViewItems являются сложными объектами. Ответ @sipwiz был отличным намеком на то, где искать...

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

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

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

Для тех, кто интересуется в основном поддержкой шаблона 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 имущество.

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

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

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

Основываясь на ответе 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!");
    }
}

если вы заполняете свойListviewчерез
ObservableCollection<ItemClass> Itemsclass ,
и ни один из приведенных выше ответов не работает для вас "как то, что случилось со мной", затем используйте:

      private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var item = ((FrameworkElement)e.OriginalSource).DataContext as ItemClass; //<< your class name here

    if (item != null)
    {
        MessageBox.Show(item.UserName + " : item Double Click handled!");
    }
}

конечно ItemClassбудет вашим именем класса setter/getter

Другие вопросы по тегам