我有一个扩展方法来订阅实现INotifyPropertyChanged的对象的PropertyChanged事件.
我希望事件只发一次.不多.
这是我的方法.
public static void OnPropertyChanged<T>(this INotifyPropertyChanged target,string propertyName,Action action) { if (target == null) { return; } PropertyChangedEventHandler handler = (obj,e) => { if (propertyName == e.PropertyName) { action(); } }; target.PropertyChanged -= handler; target.PropertyChanged += handler; }
但它不起作用.我无法删除事件处理程序,因此每次调用此方法时都会触发事件.
我尝试了不同的方法.而不是使用匿名方法,更传统的东西,像这样:
public static void OnPropertyChanged<T>(this INotifyPropertyChanged target,Action action) { if (target == null) { return; } target.PropertyChanged -= target_PropertyChanged; target.PropertyChanged += target_PropertyChanged; } static void target_PropertyChanged(object sender,PropertyChangedEventArgs e) { //do stuff here }
它只是工作正常.该事件只触发一次,但我还需要Action参数.我不能用这种方法.
任何解决方法或不同的方法来解决这个问题?静态方法中的匿名方法有什么奇怪的吗?
提前致谢.
解决方法
这是使用匿名方法作为事件处理程序的限制.它们不能像普通方法那样被删除(从技术上讲,它是通过方法组转换自动创建的委托实例),因为匿名方法被编译成编译器生成的容器类,并且每次都会创建类的新实例.
为了保留action参数,你可以创建一个容器类,它将包含你的事件处理程序的委托.该类可以在您正在使用的另一个类中声明为私有 – 或者在内部创建,也可以在“Helpers”命名空间中.它看起来像这样:
class DelegateContainer { public DelegateContainer(Action theAction,string propName) { TheAction = theAction; PopertyName = propName; } public Action TheAction { get; private set; } public string PropertyName { get; private set; } public void PropertyChangedHandler(object sender,PropertyChangedEventArgs e) { if(PropertyName == e.PropertyName) TheAction(); } }
然后,在类中创建并存储对容器的引用.您可以创建一个静态成员currentContainer,然后像这样设置处理程序:
private static DelegateContainer currentContainer; public static void OnPropertyChanged<T>(this INotifyPropertyChanged target,Action action) { if (target == null) { return; } if(currentContainer != null) target.PropertyChanged -= currentContainer.PropertyChangedHandler; currentContainer = new DelegateContainer(action,propertyName); target.PropertyChanged += currentContainer.PropertyChangedHandler; }