.net 锁定/解锁可观察采集<;T>;

.net 锁定/解锁可观察采集<;T>;,.net,observablecollection,.net,Observablecollection,我需要允许或防止修改ObservableCollection(或者至少是实现WPF绑定的INotifyCollectionChanged的类型)以及它所包含的基于业务规则的对象 我可以解决防止修改包含的对象的问题,但不确定如何防止更改集合本身。一种选择是订阅CollectionChanged事件,并在更改发生后撤消更改,但这并不优雅,对客户来说是一个令人困惑的契约 还有哪些其他方法?您可以创建自己的集合类型并继承可观测集合。这是一个潜在的选择吗 public class ReadOnlyObse

我需要允许或防止修改
ObservableCollection
(或者至少是实现WPF绑定的
INotifyCollectionChanged
的类型)以及它所包含的基于业务规则的对象

我可以解决防止修改包含的对象的问题,但不确定如何防止更改集合本身。一种选择是订阅
CollectionChanged
事件,并在更改发生后撤消更改,但这并不优雅,对客户来说是一个令人困惑的契约


还有哪些其他方法?

您可以创建自己的集合类型并继承
可观测集合。这是一个潜在的选择吗

public class ReadOnlyObservableCollection<T> : ObservableCollection<T>
{
    // method overrides with conditional logic to allow/deny changes
}
公共类ReadOnlyObservableCollection:ObservableCollection { //方法用条件逻辑重写以允许/拒绝更改 }
您可以声明自己实现ICollection(和friends)接口的类,并使基础集合成为该类的成员。您不希望继承,因为这样可能会有人简单地将对象引用强制转换为基类,而您已经失去了保护

在正常情况下,将所有更新委托给基础类,直到集合被锁定。当它被锁定时,开始抛出断言,而不是转发下面的调用。并且所有读取操作都始终被委派


这基本上是

我同意建议包装一个
可观察集合
。这是我的实现,以防对任何人有所帮助。这种方法的一个缺点是所包含对象上的ILockable.Locked是公共的,因此可以解锁单个包含的对象,如:
wrappedCollection.Item(0).Locked=false。此外,我还没有实现索引器,因为EF。如果您不使用EF,请随意添加索引器

public interface ILockable
{
    bool Locked { get; set; }
}

public class LockableObservableCollection<T> : ICollection<T>, INotifyCollectionChanged, INotifyPropertyChanged, ILockable
    where T: ILockable
{
    protected ObservableCollection<T> Collection { get; set; }

    public LockableObservableCollection()
    {
        Collection = new ObservableCollection<T>();
        Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(Collection_CollectionChanged);
        ((INotifyPropertyChanged)Collection).PropertyChanged += 
            new PropertyChangedEventHandler(LockableObservableCollection_PropertyChanged);
    }

    void LockableObservableCollection_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null) PropertyChanged(this, e);
    }

    void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (CollectionChanged != null) CollectionChanged(this, e);
    }

    public T Item(int index)
    {
        return Collection[index];
    }

    #region ICollection<T>

    public void Add(T item)
    {
        if (Locked) throw new Exception("Collection is locked.");

        Collection.Add(item);
    }

    public void Clear()
    {
        if (Locked) throw new Exception("Collection is locked.");

        Collection.Clear();
    }

    public bool Contains(T item)
    {
        return Collection.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        Collection.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return Collection.Count; }
    }

    public bool IsReadOnly
    {
        get { return Locked; }
    }

    public bool Remove(T item)
    {
        if (Locked) throw new Exception("Collection is locked.");

        bool result = Collection.Remove(item);
        return result;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Collection.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    #endregion

    #region INotifyCollectionChanged
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    #endregion

    #region IPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    private bool locked;
    public bool Locked
    {
        get
        {
            return locked;
        }
        set
        {
            if (locked != value)
            {
                locked = value;
                foreach (T t in Collection)
                {
                    t.Locked = value;
                }
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Locked"));
                }

            }
        }
    }
}
private string text;

public string Text
{
    get { return text; }
    set
    {
        if (text != value)
        {
            if (Locked) throw new Exception("This item is locked to prevent changes.");
            text = value;
        }
    }
}