WPF:ListView 添加项目时引发事件

22

我正在开发WPF应用程序,使用了ListView控件,需要在添加新项时触发一个事件。我尝试了以下代码:

var dependencyPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ListView));
        if (dependencyPropertyDescriptor != null)
        {
               dependencyPropertyDescriptor.AddValueChanged(this, ItemsSourcePropertyChangedCallback);
        }

.....

 private void ItemsSourcePropertyChangedCallback(object sender, EventArgs e)
    {
         RaiseItemsSourcePropertyChangedEvent();
    }

但是似乎仅在整个集合更改时才起作用,我阅读了这篇文章:event-fired-when-item-is-added-to-listview,但最佳答案仅适用于listBox。我尝试将代码更改为ListView,但我无法做到这一点。
希望您能帮助我。提前感谢您。

在您发布的问题的答案评论中,您会发现“修改了我的代码以使其更清晰。此外,这应该适用于任何ItemsControl(ListBox或ListView)。” - 您特别遇到了什么问题? - Slugart
@Slugart 感谢您的回复,我遇到的问题是BeginInvoke方法不接受声明中的示例。它说DispatcherPriority不存在。 - Dante
2个回答

66

请注意,这只适用于WPF Listview!

经过一些研究,我已经找到了答案,而且非常简单:

public MyControl()
{
    InitializeComponent();
    ((INotifyCollectionChanged)listView.Items).CollectionChanged +=  ListView_CollectionChanged;
}

private void ListView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)     
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
      // scroll the new item into view   
      listView.ScrollIntoView(e.NewItems[0]);
    }
}

实际上,NotifyCollectionChangedAction 枚举允许您的程序通知您有关以下任何更改的信息:Add、Move、Replace、Remove和Reset。


1
这对我不起作用。我得到了“无法将类型为'ListViewItemCollection'的对象强制转换为类型'System.Collections.Specialized.INotifyCollectionChanged'”。 - Arvo Bowen
1
对于其他好奇的人,ListView.Items 的类型是 ItemsCollection。它继承自实现了 INotifyCollectionChangedCollectionView。根据 MSDN 的说明,在 .NET 3.0 - 4.6 中都是如此。@Arvo,ListViewItemCollection 只实现了 IList、ICollection、IEnumerable,没有继承任何东西,因此会出现异常。 - DJH
也适用于 WPF Listbox。如果绑定了一个 observablecollection<string>,则第一个出现的将被带入视图!因此,如果相同的值可以多次出现,请使用一个属性设置类进行绑定(observablecollection<myclass>),并相应地设置 DisplayMemberPath。 - dba

-2

注意:此解决方案适用于WinForms ListView。

在我的情况下,我最终面临两条路的选择...

(1) 创建一个自定义ListView控件,该控件继承自ListView类。然后添加一个新事件,在任何项目被添加、删除或ListView被清除时引发。这条路看起来非常混乱和漫长。更不用提我需要用新创建的自定义ListView控件替换所有原始的ListViews的另一个重要问题了。所以我放弃了这个方案!


(2) 在每次向列表视图添加、删除或清除调用时,我还会调用另一个函数来模拟CollectionChanged事件。

创建类似事件的新函数...

private void myListViewControl_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    //The projects ListView has been changed
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            MessageBox.Show("An Item Has Been Added To The ListView!");
            break;
        case NotifyCollectionChangedAction.Reset:
            MessageBox.Show("The ListView Has Been Cleared!");
            break;
    }
}

在其他地方向ListView添加一个项目...

ListViewItem lvi = new ListViewItem("ListViewItem 1");
lvi.SubItems.Add("My Subitem 1");
myListViewControl.Items.Add(lvi);
myListViewControl_CollectionChanged(myListViewControl, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, lvi, lvi.Index));

在其他地方清除ListView...

myListViewControl.Items.Clear();
myListViewControl_CollectionChanged(myListViewControl, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

很奇怪,但丹特的解决方案对你不起作用,尤其是当你的解决方法涉及到 INotifyCollectionChanged 时。 ((INotifyCollectionChanged)MyList.Items).CollectionChanged += MyListChanged 对我有效。你确定括号放在了正确的位置吗? - Mathieu Guindon
也许它与WPF有关,但我不使用它,我正在使用WinForms。不确定,我只知道所有命名空间都已经计入,并且所有引用都可以与这些对象/类型完美配合使用。我甚至真的不知道如何将listView.Items的集合转换为INotifyCollectionChanged(不是说不能做到,只是我不懂)。除了那一部分之外,其他的看起来都很好。如果您告诉我,我非常愿意尝试一些东西。但就目前而言,我的VS 2010认为不行!;) - Arvo Bowen
2
WinForms和WPF是两个完全不同的东西;WinForms的ListView与WPF的ListView没有任何关系!WPF的ListViewItemCollection实现了INotifyCollectionChanged;这使得WPF强大的数据绑定功能能够检测列表中的更改并[几乎]自动地保持一切更新。你应该考虑放弃WinForms,尝试一下WPF - 一旦你掌握了它,你就再也不会回头了! :) - Mathieu Guindon
1
谢谢!已经注意到了。我修改了Dante的答案,出于几个原因(在顶部添加了一个注释,针对像我这样的纯C#开发人员)。一旦编辑被接受,我会投赞成票。我很快就会尝试WPF!;) 我也需要从2010年升级到2013年。嘿嘿 - Arvo Bowen
1
没问题,除非这个问题已经被标记为 [tag:wpf]...(不是我的踩) - Mathieu Guindon
哈!别担心,每个人都有自己的看法。;) 我只是添加了所有内容并留下了我的答案来帮助其他人。当我在寻找类似于我需求的解决方案时,我被引导到这里。所以我想为什么不尝试帮助下一个人呢?也许有人会从中受益。 - Arvo Bowen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接