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),却发现ListViewItem
s 及其相关的内存正在通过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。
在我的例子中,我有一个填充ListView
的Project
对象集合。这些对象包含的属性比列表中显示的要多,我打开一个 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:附加双击(在项目上)事件的主要内容,如果未能解决你的问题,请参考以下文章