/// <summary> Helps to safely raise an event. /// </summary> /// <param name="delegate">The event delegate (<see cref="EventHandler"/>, <see cref="EventHandler{T}"/></param> /// <param name="sender">The sender</param> /// <param name="e">The event arguments</param> /// <param name="uniqueId">A unique ID</param> /// <exception cref="MultiTargetInvocationException"></exception> public static void Raise(Delegate @delegate, object sender, EventArgs e, string uniqueId) { if (@delegate == null) { return; } #region simple invoke (conditional) #if (false) // simple invoke the delegate w/o any other stuff (DynamicInvoke is slow!) try{ @delegate.DynamicInvoke(new[] { sender, e }); } catch (Exception ex) { if (ObjectVM.IsInDesignMode) { return; // ignore designtime error } throw; // possible breakpoint for debug } return; #endif #endregion // var exceptions=new List<Exception>(); var exceptions = (List <Exception>)null; //don't collect, do throw directly var invocationList = @delegate.GetInvocationList(); #region Trace (conditional) #if (false) Debug.WriteLine("=>Raise event: " + "(" + invocationList.Length + " target" + (invocationList.Length != 1?"s":"") + ")"); foreach (var d in invocationList) { var targetType = d.Target.GetType().FullName; var method = d.Method.ToString(); Debug.WriteLine("=>\t" + "Target: " + targetType + " " + method); } Debug.WriteLine("=>\t" + "Raising method: " + sender.GetType().FullName + "." + new StackFrame(1).GetMethod()); // MemberPath (ObjectVM/ObjectBM) var memberPathProperty = sender.GetType().GetProperty("MemberPath"); if (memberPathProperty != null) { var memberPath = memberPathProperty.GetValue(sender, null); Debug.WriteLine("=>\t" + "MemberPath: " + memberPath); } #endif #endregion var isInvokeRequired = ApplicationDispatcher.IsInvokeRequired; foreach (var d in invocationList) { #region DEBUG (conditional) #if (false) Debug.WriteLine(string.Format("=>Raise event: #{0} {1} {2}", ++InvocationCount, DebugUtil.FormatTypeName(@delegate), "Target: " + DebugUtil.FormatTypeName(d.Target) + "." + d.Method.Name )); #endif #endregion // EXPERIMENTAL ==> // workaround for TargetInvocationException --> InvalidOperationException: // "The calling thread cannot access this object because a different thread owns it." // e.g. System.Windows.Input.CanExecuteChangedEventManager+HandlerSink, PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 if (isInvokeRequired) { if (d.Target.GetType().FullName == "System.Windows.Input.CanExecuteChangedEventManager+HandlerSink") { InvokeAppDispatcher(d, sender, e, exceptions); } else if (d.Target.GetType().FullName == "System.Windows.Data.ListCollectionView") { InvokeAppDispatcher(d, sender, e, exceptions); } /*??*/ else if (d.Target.GetType().Assembly.GetName().Name == "PresentationCore") { InvokeAppDispatcher(d, sender, e, exceptions); } else { Invoke(d, sender, e, exceptions); } } //<== else { Invoke(d, sender, e, exceptions); } } if (exceptions != null && exceptions.Count > 0) { var ex = new MultiTargetInvocationException(exceptions); #region DESIGNER if (IsInDesignMode) { // Trace.Write("=>Begin:" + exceptionCount + "######################################################################################################################################"+"\n"); Trace.Write("=>An unhandled exception has occured. Trying to continue." + "\n" + ex.ToString() + "\n"); foreach (var exception in exceptions) { Trace.Write("--------------------------------------------------------------------------------------------------------------------------------------" + "\n" + exception.ToString() + "\n"); } // Trace.Write("=>End :" + exceptionCount + "######################################################################################################################################"+"\n"); return; } #endregion throw ex; } }