我要求允许或阻止修改ObservableCollection<T>
(或至少为WPF绑定实现INotifyCollectionChanged
的类型)以及基于业务规则包含的对象。< / p>
我可以解决阻止修改包含对象的问题,但我不确定如何防止更改集合本身。一种选择是订阅CollectionChanged
事件并在事件发生后撤消更改,但这并不优雅,并且代表了与客户的混淆合同。
还有其他方法吗?
答案 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;
}
}
}