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>

ฉันจะแนบเหตุการณ์กับทุกรายการที่ถูกผูกไว้ซึ่งจะเริ่มทำงานเมื่อดับเบิลคลิกที่รายการนั้นได้อย่างไร

คำตอบ:


102

พบวิธีแก้ปัญหาจากที่นี่: 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>

ค#:

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

14
หากคุณไม่จำเป็นต้องใช้สไตล์ซ้ำคุณสามารถใส่มันลงในส่วน <ListView.Resources /> โดยตรงและลบ x: Key
David Schmitt

8
สิ่งนี้ได้ผลสำหรับฉันเช่นกัน ขอบคุณ! BTW คุณอาจต้องการหยุดการเดือดของเหตุการณ์ doubleClick ภายในตัวจัดการของคุณโดยการตั้งค่า: e.Handled = true;
Tom A

1
ฉันมีปัญหากับเรื่องนี้ นั่นคือฉันใช้ x: รูปแบบไม่ใช้คีย์ในหน้าต่างเพื่อจัดรูปแบบองค์ประกอบ UI ทั้งหมดรวมถึง ListViews ที่ใช้ในการควบคุมแบบกำหนดเองบนหน้าต่างนั้น การใส่ตัวจัดการเหตุการณ์นี้ใน xaml ของตัวควบคุมแบบกำหนดเองจะปิดใช้งานสไตล์ที่ใช้ในหน้าต่าง
Jeno Csupor

8
ด้วยความอยากรู้อยากเห็นมีวิธีอื่นในการทำเช่นนี้ที่ไม่ละเมิด MVVM หรือไม่?
Dave

13
เพื่อเป็นการเตือน: การใช้EventSetterสามารถทำให้หน่วยความจำรั่วไหลได้หากเป้าหมายของตัวจัดการมีอายุการใช้งานนานกว่าListViewItem. ฉันใช้เวลาสองสามวันที่ผ่านมาในการแก้ไขจุดบกพร่องของหน่วยความจำที่รั่วไหลอย่างรุนแรง (ครั้งละ 20mb) เพียงเพื่อจะพบว่าListViewItemหน่วยความจำและหน่วยความจำที่เกี่ยวข้องถูกรั่วไหลผ่านEventSetterไฟล์.
Zach Johnson

73

ไม่มีหน่วยความจำรั่วไหล(ไม่จำเป็นต้องยกเลิกการสมัครแต่ละรายการ)งานได้ดี:

XAML:

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

ค#:

    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

3
สิ่งนี้ไม่เพียงพอหากรายการของคุณมีวัตถุที่ซับซ้อน คุณต้องใช้ผู้ช่วยต้นไม้ภาพเพื่อค้นหา ListViewItem หลักและจากนั้นคุณสามารถใช้ datacontext
ravyoli

3
สะอาดและเรียบง่าย ขอบคุณ.
Eternal21

1
ดีมากและเป็นประโยชน์ ในกรณีของฉันฉันมีปุ่มเลือกเพิ่มเติมที่ทำหน้าที่เลือก ดังนั้นฉันจึงใช้การดับเบิลคลิกดังนี้: 'MouseDoubleClick = "SelectBtn_Click"' 'โมฆะส่วนตัว SelectBtn_Click (ผู้ส่งวัตถุ, RoutedEventArgs e) {}'
Kishore

3
นี่คือเหตุผลที่คุณมักจะเลื่อนผ่านคำตอบที่ยอมรับ ในกรณี ...
aggsol

7

วิธีแก้ปัญหาของฉันขึ้นอยู่กับคำตอบของ @ epox_subซึ่งคุณควรดูว่าจะวาง Event Handler ไว้ที่ใดใน 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 (a WPF Window) เพื่อแสดง

วัตถุของการจัดการเหตุการณ์จะได้รับการแต่งตั้งsender ListViewItemต่อจากนั้นสิ่งProjectที่ฉันต้องการเข้าถึงมีอยู่ในContentคุณสมบัติ


3

ในตัวอย่างของคุณคุณกำลังพยายามจับเมื่อรายการใน ListView ของคุณถูกเลือกหรือเมื่อคลิกที่ส่วนหัวของคอลัมน์? หากเป็นแบบเดิมคุณจะต้องเพิ่มตัวจัดการ SelectionChanged

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

หากเป็นอย่างหลังคุณจะต้องใช้เหตุการณ์ MouseLeftButtonUp หรือ MouseLeftButtonDown ร่วมกันในรายการ GridViewColumn เพื่อตรวจจับการคลิกสองครั้งและดำเนินการที่เหมาะสม หรือคุณสามารถจัดการกับเหตุการณ์บน GridView และหาข้อมูลจากที่นั่นว่าส่วนหัวของคอลัมน์ใดอยู่ใต้เมาส์


ฉันต้องการกิจกรรมในรายการที่ถูกล้อมรอบไม่ใช่ส่วนหัว
Andreas Grech

นั่นเป็นสิ่งใหม่สำหรับฉัน ขอขอบคุณที่ตอบคำถามของคุณ (และฉันจะลบคำชี้แจงกิจกรรม DoubleClick ที่ไม่มีออกจากฉัน)
Aaron Clauson

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; } })- --- ไม่จำเป็นต้องใช้การหล่อ แต่ช่วยใน ISE ให้เสร็จสมบูรณ์
BananaAcid
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.