Question

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?

 45  22054  45
1 Jan 1970

Solution

 69

A 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.


Note that the [previously] accepted answer will actually return a different ReadOnlyObservableCollection every time ReadOnlyFoo is accessed. This is wasteful and can lead to subtle bugs.

2010-05-20

Solution

 15

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>(),
                };
    }
}
2013-03-18