WPF ListView:附加双击(在项目上)事件

And*_*ech 80 c# wpf xaml

我有以下内容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>
Run Code Online (Sandbox Code Playgroud)

如何将事件附加到双击项目时将触发的每个绑定项目?

And*_*ech 97

从这里找到解决方案: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>
Run Code Online (Sandbox Code Playgroud)

C#:

protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
{
    var track = ((ListViewItem) sender).Content as Track; //Casting back to the binded Track
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您不需要重复使用该样式,可以将其直接放入<ListView.Resources />部分并删除x:Key. (12认同)
  • 作为警告:使用`EventSetter`如果其处理程序的目标比`ListViewItem`长,则可能导致内存泄漏.我花了最后几天调试严重的内存泄漏(一次20mb),结果却发现`ListViewItem'及其相关内存是通过`EventSetter`泄露的. (11认同)
  • 这对我也有用.谢谢!顺便说一句,您可能希望通过设置来停止处理程序中doubleClick事件的冒泡:e.Handled = true; (7认同)
  • 出于好奇,有没有其他方法可以做到这一点,不违反MVVM? (7认同)

epo*_*pox 63

没有内存泄漏,工作正常:

XAML:

<ListView ItemsSource="{Binding TrackCollection}" MouseDoubleClick="ListView_MouseDoubleClick" />
Run Code Online (Sandbox Code Playgroud)

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!");
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这就是为什么你总是滚动过去接受的答案。万一... (4认同)
  • 如果列表包含复杂对象,这还不够.您需要使用可视化树帮助程序来查找父ListViewItem,然后您可以从中获取datacontext (3认同)
  • 太好了,不再需要担心内存泄漏,坦率地说,它只是一个干净得多的地狱。 (2认同)
  • 干净简单。谢谢。 (2认同)

CAD*_*oke 6

我的解决方案基于@ 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!");
    }
}
Run Code Online (Sandbox Code Playgroud)

这样做的好处就是你获得了SelectedItemDataContext绑定(Track在这种情况下).选定项目有效,因为双击的第一次单击选择它.

  • 这很好用,但不幸的是,当用户双击列表视图中的空白区域时也会触发双击事件,并且由于当用户单击空白区域时未清除 SelectedItem,因此该事件将在先前选定的项目上执行。 (2认同)

Mic*_*tal 5

对于那些主要对维护 MVVM 模式感兴趣的人,我使用Andreas Grech 的答案来解决这个问题。

基本流程:

用户双击项目 -> 代码隐藏中的事件处理程序 -> 视图模型中的 ICommand

项目视图.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}"/>
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

项目视图模型.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();
    }
}
Run Code Online (Sandbox Code Playgroud)

DelegateCommand.cs 可以在这里找到。

在我的实例中,我有一个Project填充ListView. 这些对象包含的属性多于列表中显示的属性,我打开一个ProjectDetailView(WPF Window)来显示它们。

事件处理程序的对象sender是 selected ListViewItem。随后,Project我想要访问的内容包含在该Content属性中。


Cod*_*ack 5

我使用的替代方法是 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>
Run Code Online (Sandbox Code Playgroud)