web-dev-qa-db-ja.com

読み取り専用のObservableCollectionプロパティを作成するにはどうすればよいですか?

(データベースからの)オブジェクトのリストを含むビューモデルのプロパティを公開したいと思います。

このコレクションを読み取り専用にする必要があります。つまり、追加/削除などを防止したいのですが、foreachとインデクサーが機能するようにします。私の意図は、編集可能なコレクションを保持するプライベートフィールドを宣言し、読み取り専用のパブリックプロパティで参照することです。次のように

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

ただし、その構文は、コレクションへの参照の変更を妨げるだけです。追加/削除などを妨げるものではありません。

これを達成するための正しい方法は何ですか?

37
thrag

[以前]受け入れられた回答は、ReadOnlyFooにアクセスするたびに、実際にはdifferentReadOnlyObservableCollectionを返します。これは無駄であり、微妙なバグにつながる可能性があります。

望ましい解決策は次のとおりです。

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アンチパターン を参照してください。

64
Eric J.

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>(),
                };
    }
}
9
Meirion Hughes

プロパティのタイプを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>
{
}
0
Jake Pearson