Я пошел с предложениями обернуть ObservableCollection<T>
.Вот моя реализация на случай, если она кому-нибудь поможет.Одним из недостатков этого подхода является то, что 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"));
}
}
}
}
}
Содержащийся объект, который реализует 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;
}
}
}