.net中ObservableCollection的用途是什么?


227

.net中ObservableCollection的用途是什么?


1
@ alpha-mouse:您能否提供更多有关您要解决的问题的信息?这将帮助人们给您相关的例子。
Jazza

@Jazza:我刚刚更改了问题的标签=)我不是santosh的问题
alpha-mouse,2010年

3
@TheMuffinMan是的,但是与MSDN过于僵化而不是正式的方式来解释自己的创作相比,我更喜欢在stackoverflow上进行解释的方式。
Sizons

Answers:


224

ObservableCollection是一个集合,它使集合外部的代码可以知道何时发生对集合的更改(添加,移动,删除)。它在WPF和Silverlight中大量使用,但不仅限于此。代码可以添加事件处理程序以查看何时更改了集合,然后通过事件处理程序做出反应以进行一些其他处理。这可能是更改UI或执行其他操作。

下面的代码实际上没有做任何事情,但是演示了如何在类中附加处理程序,然后使用事件args对更改做出某种反应。WPF已经有许多操作,例如刷新内置的UI,因此在使用ObservableCollections时可以免费获得它们

class Handler
{
    private ObservableCollection<string> collection;

    public Handler()
    {
        collection = new ObservableCollection<string>();
        collection.CollectionChanged += HandleChange;
    }

    private void HandleChange(object sender, NotifyCollectionChangedEventArgs e)
    {
        foreach (var x in e.NewItems)
        {
            // do something
        }

        foreach (var y in e.OldItems)
        {
            //do something
        }
        if (e.Action == NotifyCollectionChangedAction.Move)
        {
            //do something
        }
    }
}

21
e.NewItemse.OldsItems可能为空,具体取决于操作。它可能会抛出NullReferenceException
dovid

7
旁注:当“动作”为“移动”时,移动的元素将同时出现在NewItems和OldItems中
bohdan_trotsenko 2015年

谢谢您:> WPF已经有很多操作,例如刷新内置的UI,以便您在使用ObservableCollections时免费获得它们
SlowLearner

157

ObservableCollection工作基本上是相似,但它实现的接口一个定期收集:

因此,当您想知道集合何时更改时,它非常有用。触发一个事件,该事件将告诉用户已添加/删除或移动了哪些条目。

更重要的是,当在表单上使用数据绑定时,它们非常有用。


54

Pro C#5.0和.NET 4.5框架开始

ObservableCollection<T>班是在具有告知外界物体时,它的内容以某种方式发生了变化的能力非常有用(您可能已经猜到,有工作 ReadOnlyObservableCollection<T>很相似,但只读性质的)。考虑到这两个类都实现了相同的核心接口,因此在许多方面,使用ObservableCollection<T>等同于使用List<T>。使ObservableCollection<T>该类唯一的原因是该类支持名为事件的事件CollectionChanged。每当插入新项目,删除(或重定位)当前项目或修改整个集合时,都会触发此事件。像任何事件一样,CollectionChanged是根据委托定义的,在这种情况下为 NotifyCollectionChangedEventHandler。该委托可以调用将对象作为第一个参数的任何方法,NotifyCollectionChangedEventArgs作为第二。考虑下面的Main()方法,该方法将填充一个包含Person对象的可观察集合,并连接 CollectionChanged事件:

class Program
{
   static void Main(string[] args)
   {
     // Make a collection to observe and add a few Person objects.
     ObservableCollection<Person> people = new ObservableCollection<Person>()
     {
        new Person{ FirstName = "Peter", LastName = "Murphy", Age = 52 },
        new Person{ FirstName = "Kevin", LastName = "Key", Age = 48 },
     };
     // Wire up the CollectionChanged event.
     people.CollectionChanged += people_CollectionChanged;
     // Now add a new item.
     people.Add(new Person("Fred", "Smith", 32));

     // Remove an item.
     people.RemoveAt(0);

     Console.ReadLine();
   }
   static void people_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
   {
       // What was the action that caused the event?
        Console.WriteLine("Action for this event: {0}", e.Action);

        // They removed something. 
        if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
        {
            Console.WriteLine("Here are the OLD items:");
            foreach (Person p in e.OldItems)
            {
                Console.WriteLine(p.ToString());
            }
            Console.WriteLine();
        }

        // They added something. 
        if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
        {
            // Now show the NEW items that were inserted.
            Console.WriteLine("Here are the NEW items:");
            foreach (Person p in e.NewItems)
            {
                Console.WriteLine(p.ToString());
            }
        }
   }
}

传入的NotifyCollectionChangedEventArgs参数定义了两个重要的属性,OldItemsNewItems,这些属性 将为您提供触发事件之前当前在集合中的项的列表以及更改中涉及的新项。但是,您只想在正确的情况下检查这些列表。回想一下,当添加,删除,重定位或重置项目时,会触发CollectionChanged事件。要发现这些动作中的哪一个触发了事件,可以使用NotifyCollectionChangedEventArgs的Action属性。可以针对以下任何NotifyCollectionChangedAction枚举成员测试Action属性:

public enum NotifyCollectionChangedAction
{
Add = 0,
Remove = 1,
Replace = 2,
Move = 3,
Reset = 4,
}

System.Collections.ObjectModel的成员


1
如果我更改集合中“ Person”的名称(不更改集合本身,是否会触发people_CollectionChanged事件?)
BKSpurgeon

25

无代码说明

对于那些想要答案而又没有任何代码(繁荣)的人,我会举手:

普通收藏-没有通知

我时不时地去纽约,妻子要求我买东西。所以我带了一张购物清单。列表上有很多东西,例如:

  1. Louis Vuitton手袋($ 5000)
  2. 克莱夫·克里斯蒂安(Clive Christian)的御用香水(215,000美元)
  3. Gucci太阳镜(2000美元)

哈哈哈好吧,我不是买那东西。所以我将它们划掉并从列表中删除,然后添加:

  1. 12打Titleist高尔夫球。
  2. 12磅保龄球。

所以我通常没有货物回家,她从不高兴。事实是,她不知道我从清单上删除了什么以及我添加到清单上的内容。她没有收到通知。

ObservableCollection-进行更改时的通知

现在,每当我从列表中删除某项内容时:她都会在手机上收到一条通知(即短信/电子邮件等)!

可观察的集合以相同的方式工作。如果您向其中添加或删除某些内容:会通知某人。当他们接到通知后,他们会打电话给您,您会全神贯注。当然,后果可以通过事件处理程序进行自定义。

总结一下!


7

最大的用途之一是您可以将UI组件绑定到一个组件,并且如果集合的内容发生更改,它们将做出适当的响应。例如,如果将ListView的ItemsSource绑定到一个,则如果您修改集合,则ListView的内容将自动更新。

编辑: 这是来自MSDN的一些示例代码: http //msdn.microsoft.com/zh-cn/library/ms748365.aspx

在C#中,将ListBox挂接到集合上可能很容易

listBox.ItemsSource = NameListData;

但是,如果您尚未将列表作为静态资源进行连接并定义了NameItemTemplate,则可能要覆盖PersonName的ToString()。例如:

public override ToString()
{
    return string.Format("{0} {1}", this.FirstName, this.LastName);
}

6

它是一个集合,主要用于通知UI集合中的更改,它支持自动通知。

主要用于WPF中,

假设您有一个带有列表框和添加按钮的UI,并且当您单击他的按钮时,一个假定类型为object的对象将被添加到obseravablecollection中,并将此集合绑定到Listbox的ItemSource,因此一旦添加了一个集合中的新项目,列表框将自动更新并在其中添加另一项。


真的发生这种情况吗?:O
Kings

5
class FooObservableCollection : ObservableCollection<Foo>
{
    protected override void InsertItem(int index, Foo item)
    {
        base.Add(index, Foo);

        if (this.CollectionChanged != null)
            this.CollectionChanged(this, new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Add, item, index);
    }
}

var collection = new FooObservableCollection();
collection.CollectionChanged += CollectionChanged;

collection.Add(new Foo());

void CollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
{
    Foo newItem = e.NewItems.OfType<Foo>().First();
}

你能解释为什么FooObservableCollection实现了集合吗?还有为什么您要检查InsertItem?
Arie

@Arie:说实话,八年后我不记得了,所以不知道。根据我在文档中看到的内容不需要任何这些,所有这些都应立即使用。
abatishchev
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.