【问题标题】:ObservableCollection<T>(List<T>)ObservableCollection<T>(列表<T>)
【发布时间】:2017-03-13 17:14:43
【问题描述】:

在 msdn 中您可以阅读:“初始化包含从指定列表复制的元素的 ObservableCollection 类的新实例。”

但我不明白这种行为:

我有一个类 Person。

public class Person
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }

    public override string ToString()
    {
        return Firstname + " " + Lastname;
    }
}

现在我创建一个人员列表。 然后我创建一个 ObservableCollection,它应该包含列表中复制的元素。

然后我更改列表中的一个人,以及 ObservableCollection 中的一个人。 这两个更改都反映在两个集合中。为什么?

最后,我将一个人添加到列表中,并将一个人添加到 OC。 添加的项目仅反映在相关集合中

public partial class MainWindow : Window
{
    private List<Person> PersonList{ get; set; }
    private ObservableCollection<Person> PersonObservableCollection { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        FillCollections();

        listbox1.ItemsSource = PersonList;
        listbox2.ItemsSource = PersonObservableCollection;            
    }


    private void FillCollections()
    {
        PersonList = LoadDataPerson();
        PersonObservableCollection = new ObservableCollection<Person>(PersonList);

        // Adding a person to the List.
        PersonList.Add(new Person() { Firstname = "added to List",});

        // Adding a person to the ObservableCollection.
        PersonObservableCollection.Add(new Person() { Firstname = "added to Observable Collection" });


        // Changing then name of the first person in the List
        Person p1 = PersonList[0];
        p1.Lastname = "changed in List";

        // Changing the name of the second person in the ObservableList
        Person p2 = PersonObservableCollection[1];
        p2.Lastname = "changed in ObservableCollection";
    }


    private List<Person> LoadDataPerson()
    {
        List<Person> personen = new List<Person>();
        personen.Add(new Person() { Firstname = "John"});
        personen.Add(new Person() { Firstname = "Will"});
        personen.Add(new Person() { Firstname = "Sam" });
        return personen;
    }
}

xaml:

<Window x:Class="ObservableCollection.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ObservableCollection"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <ListBox Grid.Column="0" x:Name="listbox1"/>
    <ListBox Grid.Column="1" x:Name="listbox2"/>

</Grid>

输出如下所示: Output

【问题讨论】:

  • 您了解reference types 的工作原理吗?特别是,您是否了解引用类型对象的列表实际上是对存在于内存中其他位置的唯一可识别对象的引用列表?

标签: c# observablecollection


【解决方案1】:

在 msdn 中您可以阅读:“初始化包含从指定列表复制的元素的 ObservableCollection 类的新实例。”

确实如此,但副本是元素,而不是它们的内容 - 意味着元素的引用。

所以现在您有两个具有相同元素的集合。
当您从列表或 observableCollection 中询问一个元素时,您将获得对同一个人实例的引用。 因此,改变它显然会反映在两者中。

当您添加一个新项目时,您将它添加到一个特定的集合中,它不会被复制到另一个集合中。

【讨论】:

    【解决方案2】:

    那里的文档可能更清楚。对于像int 这样的值类型,“复制”的含义很明显:

    初始化包含从指定列表复制的元素的ObservableCollection&lt;T&gt; 类的新实例。

    但是,在您的情况下,您有一个引用类型。正是这个引用在两个列表之间被复制,所以两个列表都指向同一个底层对象,这意味着在两个列表中都可以看到任何更新。

    【讨论】:

    • 我不确定这是不是文档的错误:程序员是否有责任了解List&lt;T&gt;,其中T 是一个引用类型,实际上是一个列表T 类型的引用?它是 .NET 类型系统的基础。如果每个涉及(甚至可能涉及!)引用类型的文档都必须涵盖这个概念,那么文档将变得不可持续地密集。
    • @phoog 哦,当然,您确实需要了解类型系统。我确实想知道是否会有更好的方式来表达“复制的元素”虽然
    • 好点。他们可以在那里添加几句话来提醒读者元素可能是参考,并链接到相关材料,以便新手读者在必要时可以继续阅读。
    【解决方案3】:

    因此,如果您查看source code for this,则底层列表正在被操纵。

        protected virtual void InsertItem(int index, T item) {
            items.Insert(index, item);
        }
    

    这只是一个例子,items 是一个私有字段:

    public class Collection<T>: IList<T>, IList, IReadOnlyList<T>
    {
        IList<T> items;
        [NonSerialized]
        private Object _syncRoot;
    
        public Collection() {
            items = new List<T>();
        }
    
        public Collection(IList<T> list) {
            if (list == null) {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list);
            }
            items = list;
        }
    

    当您修改两个集合(可观察的集合和原始集合)时,您可以清楚地看到,更改将反映在两者中。

    ObservableCollection 所做的一切都是代理INotifyPropertyChanged

    【讨论】:

      猜你喜欢
      • 2012-05-28
      • 1970-01-01
      • 2011-09-09
      • 2011-05-15
      • 2010-10-02
      • 1970-01-01
      • 2011-11-24
      • 1970-01-01
      • 2011-04-04
      相关资源
      最近更新 更多