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

Posted

技术标签:

【中文标题】WPF ListView:附加双击(在项目上)事件【英文标题】:WPF ListView: Attaching a double-click (on an item) event 【发布时间】:2010-10-18 05:04:13 【问题描述】:

我有以下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>

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

【问题讨论】:

【参考方案1】:

从这里找到解决方案: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

【讨论】:

如果不需要复用样式,可以直接放到部分,去掉x:Key。 这对我也有用。谢谢!顺便说一句,您可能希望通过设置来停止处理程序中 doubleClick 事件的冒泡: e.Handled = true; 我对此有疑问。也就是说,我在窗口中使用 x:Key-less 样式来设置所有 UI 元素的样式,包括在该窗口上的自定义控件中使用的 ListView。将此事件处理程序放在自定义控件的 xaml 中会禁用在窗口中应用的样式。 只是出于好奇,还有其他不违反 MVVM 的方法吗? 作为警告:如果其处理程序的目标寿命比ListViewItem 长,使用EventSetter 可能会导致内存泄漏。过去几天我调试了一个严重的内存泄漏(一次 20mb),却发现ListViewItems 及其相关的内存正在通过EventSetter 泄漏。【参考方案2】:

没有内存泄漏(无需取消订阅每个项目),工作正常:

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

【讨论】:

非常棒,再也不用担心内存泄漏了,坦率地说,它只是干净多了。 如果您的列表包含复杂对象,这还不够。您需要使用可视化树助手来查找父 ListViewItem 并从那里获取数据上下文 干净简单。谢谢。 非常好,乐于助人。就我而言,我有一个额外的选择按钮来执行选择操作。所以我使用双击如下: 'MouseDoubleClick="SelectBtn_Click"' 'private void SelectBtn_Click(object sender, RoutedEventArgs e) ' 这就是为什么你总是滚动过去接受的答案。以防万一……【参考方案3】:

我的解决方案是基于@epox_sub's answer,您应该查看在 XAML 中放置事件处理程序的位置。代码隐藏对我不起作用,因为我的 ListViewItems 是复杂对象。 @sipwiz's answer 是一个很好的提示,告诉你去哪里看......

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)。 Selected Item 之所以有效,是因为第一次双击时会选中它。

【讨论】:

这很好用,但不幸的是,当用户双击列表视图中的空白区域时也会触发双击事件,并且由于用户单击空白区域时未清除 SelectedItem,因此该事件在先前选择的项目上执行。【参考方案4】:

我使用的替代方法是事件到命令,

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

【讨论】:

【参考方案5】:

对于那些对主要维护 MVVM 模式感兴趣的人,我使用了Andreas Grech's answer 来解决问题。

基本流程:

用户双击项目 -> 后面代码中的事件处理程序 -> ICommand in 查看模型

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();
    

可以在here找到DelegateCommand.cs。

在我的例子中,我有一个填充ListViewProject 对象集合。这些对象包含的属性比列表中显示的要多,我打开一个 ProjectDetailView(一个 WPF Window)来显示它们。

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

【讨论】:

【参考方案6】:

在您的示例中,您是否尝试捕获 ListView 中的项目何时被选中或列标题被单击?如果是前者,您将添加一个 SelectionChanged 处理程序。

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

如果是后者,您必须在 GridViewColumn 项目上使用 MouseLeftButtonUp 或 MouseLeftButtonDown 事件的某种组合来检测双击并采取适当的操作。或者,您可以处理 GridView 上的事件并从那里计算出鼠标下方的列标题。

【讨论】:

我想要一个关于有界项目的事件,而不是标题 这对我来说是新的。感谢您提出您的答案(我会删除我的 no DoubleClick 事件声明)。【参考方案7】:

在epox_spb's answer 的基础上,我添加了一个检查以避免双击 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 完成

以上是关于WPF ListView:附加双击(在项目上)事件的主要内容,如果未能解决你的问题,请参考以下文章

WPF ListView和ListBox等双击事件问题

WPF入门教程系列二十——ListView示例

我如何在WPF DataGrid上处理单元格双击事件,相当于Windows DataGrid的事件?

WPF-单击ListView中的项目

React Native ListView:前置项目

c# 如何双击listview 的项可变成编辑状态?