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
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?
The [previously] accepted answer will actually return a different ReadOnlyObservableCollection every time ReadOnlyFoo is accessed. This is wasteful and can lead to subtle bugs.
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.
I don't like using ReadOnlyObservableCollection<T>
as it seems like a mistake / broken class; I prefer a contract based approach instead.
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>(), }; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With