I'd like to expose a property on a view model that contains a list of objects (from database).
我想在包含对象列表(来自数据库)的视图模型上公开一个属性。
I need this collection to be read-only. That is, I want to prevent Add/Remove, etc. But allow the foreach and indexers to work. My intent is to declare a private field holding the editable collection and reference it with a read-only Public Property. As follows
我需要这个集合是只读的。也就是说,我想防止添加/删除等等。但是允许foreach和索引器工作。我的意图是声明一个包含可编辑集合的私有字段,并使用只读公共属性引用它。如下
public ObservableCollection<foo> CollectionOfFoo {
get {
return _CollectionOfFoo;
}
}
However, that syntax just prevents changing the reference to the collection. It doesn't prevent add/remove, etc.
但是,这种语法只会阻止对集合的引用的更改。它不阻止添加/删除等。
What is the right way to accomplish this?
什么是实现这一目标的正确方法?
5 个解决方案
#1
57
The [previously] accepted answer will actually return a different ReadOnlyObservableCollection every time ReadOnlyFoo is accessed. This is wasteful and can lead to subtle bugs.
[先前]接受的答案实际上会在每次访问ReadOnlyFoo时返回不同的ReadOnlyObservableCollection。这是一种浪费,可能会导致细微的错误。
A preferable solution is:
一个更可取的措施是:
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;
}
See ReadOnlyObservableCollection anti-pattern for a full discussion.
详细讨论请参阅ReadOnlyObservableCollection反模式。
#2
7
I don't like using ReadOnlyObservableCollection<T>
as it seems like a mistake / broken class; I prefer a contract based approach instead.
我不喜欢使用ReadOnlyObservableCollection
Here is what I use that allows for covarience:
下面是我使用的考虑协变的方法:
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>(),
};
}
}
#3
0
You could change the type of your property to be an IEnumerable:
您可以将您的属性类型更改为IEnumerable:
public IEnumerable<foo> CollectionOfFoo {
get {
return _CollectionOfFoo;
}
}
I don't believe there is a standard interface that exposes an indexer. If you need it you could write an interface and extend ObservableCollection to implement it:
我不相信有一个公开索引器的标准接口。如果您需要它,您可以编写一个接口并扩展ObservableCollection来实现它:
public interface IIndexerCollection<T> : IEnumerable<T>
{
T this[int i]
{
get;
}
}
public class IndexCollection<T> : ObservableCollection<T>, IIndexerCollection<T>
{
}
#4
-1
You could also override the list class that you're using and put an immutable flag in one of the constructors such that it will not add/remove if it was constructed with the immutable flag set to true.
您还可以重写正在使用的list类,并在其中一个构造函数中放置一个不可变标志,这样,如果它是用设置为true的不可变标志构造的,它就不会添加/删除。
#5
-1
Use ReadOnlyObservableCollection< T >
使用ReadOnlyObservableCollection < T >
public ReadOnlyObservableCollection<T> ReadOnlyFoo
{
get { return new ReadOnlyObservableCollection<T> (_CollectionOfFoo); }
}
As has been pointed out, please use Eric J's answer as this one mistakenly is returning a new instance every time.
正如已经指出的,请使用Eric J的答案,因为这个错误每次都返回一个新的实例。
#1
57
The [previously] accepted answer will actually return a different ReadOnlyObservableCollection every time ReadOnlyFoo is accessed. This is wasteful and can lead to subtle bugs.
[先前]接受的答案实际上会在每次访问ReadOnlyFoo时返回不同的ReadOnlyObservableCollection。这是一种浪费,可能会导致细微的错误。
A preferable solution is:
一个更可取的措施是:
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;
}
See ReadOnlyObservableCollection anti-pattern for a full discussion.
详细讨论请参阅ReadOnlyObservableCollection反模式。
#2
7
I don't like using ReadOnlyObservableCollection<T>
as it seems like a mistake / broken class; I prefer a contract based approach instead.
我不喜欢使用ReadOnlyObservableCollection
Here is what I use that allows for covarience:
下面是我使用的考虑协变的方法:
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>(),
};
}
}
#3
0
You could change the type of your property to be an IEnumerable:
您可以将您的属性类型更改为IEnumerable:
public IEnumerable<foo> CollectionOfFoo {
get {
return _CollectionOfFoo;
}
}
I don't believe there is a standard interface that exposes an indexer. If you need it you could write an interface and extend ObservableCollection to implement it:
我不相信有一个公开索引器的标准接口。如果您需要它,您可以编写一个接口并扩展ObservableCollection来实现它:
public interface IIndexerCollection<T> : IEnumerable<T>
{
T this[int i]
{
get;
}
}
public class IndexCollection<T> : ObservableCollection<T>, IIndexerCollection<T>
{
}
#4
-1
You could also override the list class that you're using and put an immutable flag in one of the constructors such that it will not add/remove if it was constructed with the immutable flag set to true.
您还可以重写正在使用的list类,并在其中一个构造函数中放置一个不可变标志,这样,如果它是用设置为true的不可变标志构造的,它就不会添加/删除。
#5
-1
Use ReadOnlyObservableCollection< T >
使用ReadOnlyObservableCollection < T >
public ReadOnlyObservableCollection<T> ReadOnlyFoo
{
get { return new ReadOnlyObservableCollection<T> (_CollectionOfFoo); }
}
As has been pointed out, please use Eric J's answer as this one mistakenly is returning a new instance every time.
正如已经指出的,请使用Eric J的答案,因为这个错误每次都返回一个新的实例。