41

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

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

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

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

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

4

5 に答える 5

68

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

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

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

于 2010-05-20T13:57:33.197 に答える
11

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>(),
                };
    }
}
于 2013-03-18T10:21:59.553 に答える
0

プロパティのタイプを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>
{
}
于 2009-11-19T14:34:47.743 に答える
-1

使用しているリストクラスをオーバーライドし、コンストラクターの1つに不変フラグを設定して、不変フラグをtrueに設定して構築された場合に追加/削除されないようにすることもできます。

于 2009-11-19T14:44:24.527 に答える
-1

ReadOnlyObservableCollection<T>を使用します

public ReadOnlyObservableCollection<T> ReadOnlyFoo
{
    get { return new ReadOnlyObservableCollection<T> (_CollectionOfFoo); }
}

指摘されているように、これは誤って毎回新しいインスタンスを返すため、EricJの回答を使用してください。

于 2009-11-19T16:16:48.227 に答える