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>

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

Answers:


101

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

13
如果不需要重复使用样式,则可以将其直接放入<ListView.Resources />部分并删除x:Key。
David Schmitt,2009年

8
这也对我有用。谢谢!顺便说一句,您可能希望通过设置以下内容来停止处理程序中doubleClick事件的冒泡:e.Handled = true;
2009年

1
我对此有疑问。也就是说,我在窗口中使用x:Key-less样式来设置所有UI元素的样式,包括该窗口的自定义控件中使用的ListViews。将此事件处理程序放在自定义控件的xaml中,将禁用窗口中应用的样式。
杰诺·乔普

8
只是出于好奇,还有另一种不违反MVVM的方法吗?
戴夫

13
警告:如果使用,EventSetter则如果其处理程序的目标寿命比更长,可能会导致内存泄漏ListViewItem。最近几天,我调试了一次严重的内存泄漏(一次20mb),才发现ListViewItems及其关联的内存正在通过泄漏EventSetter
扎克·约翰逊

69

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

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

1
太好了,不再需要担心内存泄漏,而且坦率地说,这只是清洁工的地狱。
ean5533 '11

3
如果列表包含复杂的对象,这还不够。您需要使用可视化树助手来找到父级ListViewItem,然后可以从那里获取数据
上下文

3
干净简单。谢谢。
Eternal21

1
非常好,乐于助人。就我而言,我还有执行选择操作的附加选择按钮。因此,我按如下方式使用了双击:'MouseDoubleClick =“ SelectBtn_Click”''私有无效SelectBtn_Click(object sender,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模式感兴趣的人,我使用了Andreas Grech的答案来解决。

基本流程:

用户双击项目->后面代码中的事件处理程序->视图模型中的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事件处理程序的对象是selected ListViewItem。随后,Project我要访问的包含在该Content属性内。


3

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

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

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


我想要一个有界项目,而不是标题上的事件
Andreas Grech

对我来说这是新的。感谢您提出答案(我将删除我的no 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; } })--不需要
强制转换,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.