WPF ListView: Đính kèm sự kiện nhấp đúp (vào một mục)


85

Tôi có những thứ sau 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>

Làm cách nào tôi có thể đính kèm một sự kiện vào mọi mục liên kết sẽ kích hoạt khi nhấp đúp vào mục đó?

Câu trả lời:


101

Tìm thấy giải pháp từ đây: 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
Nếu bạn không cần sử dụng lại kiểu, bạn có thể đặt nó trực tiếp vào phần <ListView.Resources /> và xóa x: Key.
David Schmitt

8
Điều này cũng làm việc cho tôi. Cảm ơn! BTW, có thể bạn sẽ muốn ngăn sự kiện doubleClick nổi lên trong trình xử lý của mình bằng cách đặt: e.Handled = true;
Tom A

1
Tôi có một vấn đề với thứ này. Đó là, tôi sử dụng x: Key-less styles trong cửa sổ để tạo kiểu cho tất cả các phần tử UI, bao gồm cả các ListView được sử dụng trong một điều khiển tùy chỉnh trên cửa sổ đó. Đặt trình xử lý sự kiện này trong xaml của điều khiển tùy chỉnh sẽ vô hiệu hóa kiểu được áp dụng trong cửa sổ.
Jeno Csupor

8
Chỉ vì tò mò, có cách nào khác để làm điều này mà không vi phạm MVVM không?
Dave

13
Như một cảnh báo: sử dụng một EventSettercó thể dẫn đến rò rỉ bộ nhớ nếu mục tiêu của trình xử lý của nó sống lâu hơn ListViewItem. Tôi đã dành vài ngày qua để gỡ lỗi lỗi rò rỉ bộ nhớ nghiêm trọng (20mb mỗi lần), chỉ để tìm ra rằng ListViewItems và bộ nhớ liên quan của chúng đã bị rò rỉ thông qua một EventSetter.
Zach Johnson

69

Không bị rò rỉ bộ nhớ (không cần hủy đăng ký từng mục) , hoạt động tốt:

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
Tuyệt vời, không cần phải lo lắng về việc rò rỉ bộ nhớ, và thành thật mà nói, nó chỉ là một địa ngục của rất nhiều dọn dẹp.
ean5533 12/11/12

3
Điều này là không đủ nếu danh sách của bạn chứa một đối tượng phức tạp. Bạn cần sử dụng trình trợ giúp dạng cây trực quan để tìm ListViewItem cha và từ đó bạn có thể lấy dữ liệu
ravyoli

3
Sạch sẽ và đơn giản. Cảm ơn.
Eternal 21

1
Rất hay và hữu ích. Trong trường hợp của tôi, tôi có nút chọn bổ sung để thực hiện hành động chọn. Vì vậy, tôi đã sử dụng double click như sau: 'MouseDoubleClick = "SelectBtn_Click"' 'private void SelectBtn_Click (object sender, RoutedEventArgs e) {}'
Kishore

3
Đây là lý do tại sao bạn luôn cuộn qua câu trả lời được chấp nhận. Chỉ trong trường hợp ...
aggsol

7

Giải pháp của tôi dựa trên câu trả lời của @ epox_sub mà bạn nên xem xét vị trí đặt Trình xử lý sự kiện trong XAML. Đoạn mã phía sau không phù hợp với tôi vì tôi ListViewItemslà các đối tượng phức tạp. Câu trả lời của @ ngụmwiz là một gợi ý tuyệt vời cho việc tìm kiếm ở đâu ...

void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var item = ListView.SelectedItem as Track;
    if (item != null)
    {
      MessageBox.Show(item + " Double Click handled!");
    }
}

Phần thưởng với điều này là bạn nhận được SelectedItemràng buộc DataContext của ( Tracktrong trường hợp này). Mục đã Chọn hoạt động bởi vì lần nhấp đầu tiên của nhấp đúp chuột sẽ chọn nó.


4

Đối với những người quan tâm đến việc duy trì hầu hết mô hình MVVM, tôi đã sử dụng câu trả lời của Andreas Grech để giải quyết vấn đề.

Luồng cơ bản:

Người dùng nhấp đúp vào mục -> Trình xử lý sự kiện trong mã phía sau -> ICommand trong mô hình xem

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 có thể được tìm thấy ở đây .

Trong ví dụ của tôi, tôi có một tập hợp các Projectđối tượng điền vào ListView. Các đối tượng này chứa nhiều thuộc tính hơn được hiển thị trong danh sách và tôi mở một ProjectDetailView(một WPF Window) để hiển thị chúng.

Đối sendertượng của trình xử lý sự kiện được chọn ListViewItem. Sau đó, cái Projectmà tôi muốn truy cập được chứa trong thuộc Contenttính.


3

Trong ví dụ của bạn, bạn đang cố gắng nắm bắt khi một mục trong ListView của bạn được chọn hoặc khi một tiêu đề cột được nhấp vào? Nếu đó là cái cũ, bạn sẽ thêm một trình xử lý SelectionChanged.

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

Nếu đó là sự kiện thứ hai, bạn sẽ phải sử dụng một số kết hợp của sự kiện MouseLeftButtonUp hoặc MouseLeftButtonDown trên các mục GridViewColumn để phát hiện nhấp đúp và thực hiện hành động thích hợp. Ngoài ra, bạn có thể xử lý các sự kiện trên GridView và từ đó tìm ra tiêu đề cột nào dưới con chuột.


Tôi muốn một sự kiện vào các mục bị chặn, không phải là tiêu đề
Andreas Grech

Đó là một cái mới đối với tôi. Cảm ơn bạn đã đưa ra câu trả lời (và tôi sẽ xóa không có tuyên bố sự kiện DoubleClick nào khỏi tôi).
Aaron Clauson

3

Thay thế mà tôi đã sử dụng là Sự kiện Để Chỉ huy,

<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

Dựa trên câu trả lời của epox_spb , tôi đã thêm vào một kiểm tra để tránh lỗi khi nhấp đúp vào tiêu đề 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!");
    }
}

rất tuyệt - hoạt động với 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; } })--- Truyền không cần thiết nhưng giúp ISE hoàn thành
BananaAcid
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.