People sometimes forget that the event handler is MultiCastDelegate and therefore has all the information about each subscriber that we need to handle this situation gracefully, without the need for an excessive penalty for Invoke + Synchronization performance. I use code like this:
using System.ComponentModel; // ... public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { var e = new PropertyChangedEventArgs(propertyName); foreach (EventHandler h in handler.GetInvocationList()) { var synch = h.Target as ISynchronizeInvoke; if (synch != null && synch.InvokeRequired) synch.Invoke(h, new object[] { this, e }); else h(this, e); } } }
What he does is simple, but I remember that I almost tore my brain, and then tried to find the best way to do it.
First, it "captures" the event handler in the local property to avoid any race conditions.
If the handler is not null (one subscriber exists in leasing), it prepares the event arguments and then iterates through the call list of this multicast delegate.
The call list has a target property that is an event subscriber. If this subscriber implements ISynchronizeInvoke (all user interface controls implement it), we then check its InvokeRequired property, and it is true, we just call it by passing the delegate and parameters. A call to this method synchronizes the call in the user interface thread.
Otherwise, we simply invoke the event handler delegate directly.
Loudenvier
source share