Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a read-only ObservableCollection property?

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?

like image 628
thrag Avatar asked Nov 19 '09 14:11

thrag


2 Answers

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.

like image 164
Eric J. Avatar answered Oct 09 '22 16:10

Eric J.


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>(),                 };     } } 
like image 38
Meirion Hughes Avatar answered Oct 09 '22 16:10

Meirion Hughes