锁定/解锁ObservableCollection <t> </t>

时间:2012-01-26 01:50:49

标签: .net observablecollection

我要求允许或阻止修改ObservableCollection<T>(或至少为WPF绑定实现INotifyCollectionChanged的类型)以及基于业务规则包含的对象。< / p>

我可以解决阻止修改包含对象的问题,但我不确定如何防止更改集合本身。一种选择是订阅CollectionChanged事件并在事件发生后撤消更改,但这并不优雅,并且代表了与客户的混淆合同。

还有其他方法吗?

3 个答案:

答案 0 :(得分:3)

您可以声明自己的类来实现ICollection(和朋友)接口,并让底层集合成为该类的成员。你不想继承,因为那时有人可能只是简单地将对象引用转换为基类,你就失去了保护。

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

这基本上是a decorator pattern

答案 1 :(得分:2)

您可以创建自己的集合类型并继承ObservableCollection<T>。这是一个潜在的选择吗?

public class ReadOnlyObservableCollection<T> : ObservableCollection<T>
{
    // method overrides with conditional logic to allow/deny changes
}

答案 2 :(得分:2)

我接受了包裹ObservableCollection<T>的建议。这是我的实施,以防它帮助任何人。这种方法的一个缺点是ILockable.Locked包含的对象是公共的,因此单个包含的对象可以解锁,如:wrappedCollection.Item(0).Locked = false;。另外,我还没有实现索引器,因为EF chokes on indexers。如果您不使用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"));
                }

            }
        }
    }
}

实现ILockable的包含对象仍必须强制执行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;
        }
    }
}