我创建了一个继承列表的Class EventList ,每当添加,插入或删除某些内容时都会触发事件:
public class EventList<T> : List<T>
{
public event ListChangedEventDelegate ListChanged;
public delegate void ListChangedEventDelegate();
public new void Add(T item)
{
base.Add(item);
if (ListChanged != null
&& ListChanged.GetInvocationList().Any())
{
ListChanged();
}
}
...
}
在片刻,我将它用作这样的属性:
public EventList List
{
get { return m_List; }
set
{
m_List.ListChanged -= List_ListChanged;
m_List = value;
m_List.ListChanged += List_ListChanged;
List_ListChanged();
}
}
现在我的问题是,我可以以某种方式处理是否有新的Object被引用或阻止它,所以我不必在setter中进行事件连接吗?
当然,我可以将属性更改为“私有集”,但我希望能够将该类用作变量。
答案 0 :(得分:16)
您很少在类中创建集合类的新实例。实例化一次并清除它而不是创建新列表。 (并使用ObservableCollection,因为它已经继承了INotifyCollectionChanged接口)
private readonly ObservableCollection<T> list;
public ctor() {
list = new ObservableCollection<T>();
list.CollectionChanged += listChanged;
}
public ObservableCollection<T> List { get { return list; } }
public void Clear() { list.Clear(); }
private void listChanged(object sender, NotifyCollectionChangedEventArgs args) {
// list changed
}
这样你只需连接事件一次,并且可以通过调用clear方法“重置它”,而不是检查属性的set访问器中的前一个列表的null或相等。
使用C#6中的更改,您可以从没有支持字段的构造函数中指定get属性(支持字段是隐式的)
因此上面的代码可以简化为
public ctor() {
List = new ObservableCollection<T>();
List.CollectionChanged += OnListChanged;
}
public ObservableCollection<T> List { get; }
public void Clear()
{
List.Clear();
}
private void OnListChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// react to list changed
}
答案 1 :(得分:10)
ObservableCollection是一个带有CollectionChanged事件的List
ObservableCollection.CollectionChanged Event
关于如何连接事件处理程序,请参阅Patrick的回答。 +1
不确定您要查找的是什么,但我将其用于一个集合,其中包含一个在添加,删除和更改时触发的事件。
public class ObservableCollection<T>: INotifyPropertyChanged
{
private BindingList<T> ts = new BindingList<T>();
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged( String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public BindingList<T> Ts
{
get { return ts; }
set
{
if (value != ts)
{
Ts = value;
if (Ts != null)
{
ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
{
OnListChanged(this);
};
}
NotifyPropertyChanged("Ts");
}
}
}
private static void OnListChanged(ObservableCollection<T> vm)
{
// this will fire on add, remove, and change
// if want to prevent an insert this in not the right spot for that
// the OPs use of word prevent is not clear
// -1 don't be a hater
vm.NotifyPropertyChanged("Ts");
}
public ObservableCollection()
{
ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
{
OnListChanged(this);
};
}
}
答案 2 :(得分:5)
如果您不想或不能转换为Observable Collection,请尝试以下方法:
public class EventList<T> : IList<T> /* NOTE: Changed your List<T> to IList<T> */
{
private List<T> list; // initialize this in your constructor.
public event ListChangedEventDelegate ListChanged;
public delegate void ListChangedEventDelegate();
private void notify()
{
if (ListChanged != null
&& ListChanged.GetInvocationList().Any())
{
ListChanged();
}
}
public new void Add(T item)
{
list.Add(item);
notify();
}
public List<T> Items {
get { return list; }
set {
list = value;
notify();
}
}
...
}
现在,对于您的媒体资源,您应该可以将代码缩减为:
public EventList List
{
get { return m_List.Items; }
set
{
//m_List.ListChanged -= List_ListChanged;
m_List.Items = value;
//m_List.ListChanged += List_ListChanged;
//List_ListChanged();
}
}
为什么呢?在EventList.Items中设置任何内容都将调用您的私有notify()
例程。
答案 3 :(得分:0)
当有人从IList.add(object)调用Generic方法时,我有一个解决方案。这样你也会收到通知。
using System;
using System.Collections;
using System.Collections.Generic;
namespace YourNamespace
{
public class ObjectDoesNotMatchTargetBaseTypeException : Exception
{
public ObjectDoesNotMatchTargetBaseTypeException(Type targetType, object actualObject)
: base(string.Format("Expected base type ({0}) does not match actual objects type ({1}).",
targetType, actualObject.GetType()))
{
}
}
/// <summary>
/// Allows you to react, when items were added or removed to a generic List.
/// </summary>
public abstract class NoisyList<TItemType> : List<TItemType>, IList
{
#region Public Methods
/******************************************/
int IList.Add(object item)
{
CheckTargetType(item);
Add((TItemType)item);
return Count - 1;
}
void IList.Remove(object item)
{
CheckTargetType(item);
Remove((TItemType)item);
}
public new void Add(TItemType item)
{
base.Add(item);
OnItemAdded(item);
}
public new bool Remove(TItemType item)
{
var result = base.Remove(item);
OnItemRemoved(item);
return result;
}
#endregion
# region Private Methods
/******************************************/
private static void CheckTargetType(object item)
{
var targetType = typeof(TItemType);
if (item.GetType().IsSubclassOf(targetType))
throw new ObjectDoesNotMatchTargetBaseTypeException(targetType, item);
}
#endregion
#region Abstract Methods
/******************************************/
protected abstract void OnItemAdded(TItemType addedItem);
protected abstract void OnItemRemoved(TItemType removedItem);
#endregion
}
}
答案 4 :(得分:0)
如果ObservableCollection不是您的解决方案,您可以尝试:
A)实现一个自定义EventArgs,它将在触发事件时包含新的Count属性。
public class ChangeListCountEventArgs : EventArgs
{
public int NewCount
{
get;
set;
}
public ChangeListCountEventArgs(int newCount)
{
NewCount = newCount;
}
}
B)实现从List继承的自定义List,并根据您的需要重新定义Count属性和构造函数:
public class CustomList<T> : List<T>
{
public event EventHandler<ChangeListCountEventArgs> ListCountChanged;
public new int Count
{
get
{
ListCountChanged?.Invoke(this, new ChangeListCountEventArgs(base.Count));
return base.Count;
}
}
public CustomList()
{ }
public CustomList(List<T> list) : base(list)
{ }
public CustomList(CustomList<T> list) : base(list)
{ }
}
C)最后订阅您的活动:
var myList = new CustomList<YourObject>();
myList.ListCountChanged += (obj, e) =>
{
// get the count thanks to e.NewCount
};