关于c#:WPF ListView:附加双击(在项目上)事件

WPF ListView: Attaching a double-click (on an item) event

我有以下ListView

1
2
3
4
5
6
7
8
9
10
11
12
13
<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>

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


从这里找到解决方案:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/3d0eaa54-09a9-4c51-8677-8e90577e7bac/

XAML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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#:

1
2
3
4
protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
{
    var track = ((ListViewItem) sender).Content as Track; //Casting back to the binded Track
}


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

XAML:

1
<ListView ItemsSource="{Binding TrackCollection}" MouseDoubleClick="ListView_MouseDoubleClick" />

C#:

1
2
3
4
5
6
7
8
    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的答案很好地暗示了在哪里看...

1
2
3
4
5
6
7
8
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)。选定项目起作用是因为双击的第一笔选中了它。


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

Basic flow:

User double-clicks item -> Event handler in code behind -> ICommand in
view model

ProjectView.xaml:

1
2
3
4
5
6
7
8
9
10
<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:

1
2
3
4
5
6
7
8
9
10
11
12
13
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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属性中。


我使用的替代方法是Event To Command,

1
2
3
4
5
6
7
8
9
<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>

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

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

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


在epox_spb的答案的基础上,我添加了一个检查以避免双击GridViewColumn标头中的错误。

1
2
3
4
5
6
7
8
void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var dataContext = ((FrameworkElement)e.OriginalSource).DataContext;
    if (dataContext is Track)
    {
        MessageBox.Show("Item's Double Click handled!");
    }
}