41

我想在包含对象列表(来自数据库)的视图模型上公开一个属性。

我需要这个集合是只读的。也就是说,我想阻止添加/删除等。但允许 foreach 和索引器工作。我的意图是声明一个包含可编辑集合的私有字段并使用只读公共属性引用它。如下

public ObservableCollection<foo> CollectionOfFoo { 
     get { 
         return _CollectionOfFoo;
     }
}

但是,该语法只是防止更改对集合的引用。它不会阻止添加/删除等。

实现这一目标的正确方法是什么?

4

5 回答 5

68

每次访问 ReadOnlyFoo 时,[以前]接受的答案实际上将返回不同的 ReadOnlyObservableCollection。这很浪费,并且可能导致细微的错误。

一个优选的解决方案是:

public class Source
{
    Source()
    {
        m_collection = new ObservableCollection<int>();
        m_collectionReadOnly = new ReadOnlyObservableCollection<int>(m_collection);
    }
 
    public ReadOnlyObservableCollection<int> Items
    {
        get { return m_collectionReadOnly; }
    }
 
    readonly ObservableCollection<int> m_collection;
    readonly ReadOnlyObservableCollection<int> m_collectionReadOnly;
}

有关完整讨论,请参阅ReadOnlyObservableCollection 反模式

于 2010-05-20T13:57:33.197 回答
11

我不喜欢使用ReadOnlyObservableCollection<T>它,因为它看起来像是一个错误/损坏的课程;我更喜欢基于合同的方法。

这是我使用的允许协方差的方法:

public interface INotifyCollection<T> 
       : ICollection<T>, 
         INotifyCollectionChanged
{}

public interface IReadOnlyNotifyCollection<out T> 
       : IReadOnlyCollection<T>, 
         INotifyCollectionChanged
{}

public class NotifyCollection<T> 
       : ObservableCollection<T>, 
         INotifyCollection<T>, 
         IReadOnlyNotifyCollection<T>
{}

public class Program
{
    private static void Main(string[] args)
    {
        var full = new NotifyCollection<string>();
        var readOnlyAccess = (IReadOnlyCollection<string>) full;
        var readOnlyNotifyOfChange = (IReadOnlyNotifyCollection<string>) full;


        //Covarience
        var readOnlyListWithChanges = 
            new List<IReadOnlyNotifyCollection<object>>()
                {
                    new NotifyCollection<object>(),
                    new NotifyCollection<string>(),
                };
    }
}
于 2013-03-18T10:21:59.553 回答
0

您可以将属性的类型更改为 IEnumerable:

public IEnumerable<foo> CollectionOfFoo { 
     get { 
         return _CollectionOfFoo;
     }
}

我不相信有一个公开索引器的标准接口。如果你需要它,你可以编写一个接口并扩展 ObservableCollection 来实现它:

public interface IIndexerCollection<T> : IEnumerable<T>
{
    T this[int i]
    {
        get;
    }
}

public class IndexCollection<T> : ObservableCollection<T>, IIndexerCollection<T>
{
}
于 2009-11-19T14:34:47.743 回答
-1

您还可以覆盖您正在使用的列表类,并在其中一个构造函数中放置一个不可变标志,这样如果它是在将不可变标志设置为 true 的情况下构造的,它就不会添加/删除。

于 2009-11-19T14:44:24.527 回答
-1

使用ReadOnlyObservableCollection<T>

public ReadOnlyObservableCollection<T> ReadOnlyFoo
{
    get { return new ReadOnlyObservableCollection<T> (_CollectionOfFoo); }
}

正如已经指出的那样,请使用 Eric J 的答案,因为这一次错误地每次都返回一个新实例。

于 2009-11-19T16:16:48.227 回答