Example #1
0
        /// <summary>
        /// Raises the specified event handler ensuring the event is received by each subscriber.
        /// </summary>
        /// <param name="handler">The event handler to raise.</param>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">An <see cref="PropertyChangingEventArgs"/> that contains the event data.</param>
        /// <exception cref="AggregateException">The exception is thrown by at least one of the subscribers.</exception>
        public static void RaiseSafe(PropertyChangingEventHandler handler, object sender, PropertyChangingEventArgs e)
        {
            if (handler != null)
            {
                List <Exception> errors = null;

                Delegate[] list = handler.GetInvocationList();
                for (int i = 0; i < list.Length; i++)
                {
                    try
                    {
                        (list[i] as PropertyChangingEventHandler)(sender, e);
                    }
                    catch (Exception exception)
                    {
                        if (errors == null)
                        {
                            errors = new List <Exception>(1);
                        }

                        errors.Add(exception);
                    }
                }

                if (errors != null)
                {
                    throw Error.Aggregate(errors.ToArray());
                }
            }
        }
        /// <summary>
        /// Raises an event safely, ensuring that all handlers are called on the proper thread, and any exceptions do not prevent other handlers being called.
        /// </summary>
        /// <param name="handler">The event to raise.</param>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="propertyName">The name of the property relating to this event.</param>
        /// <exception cref="ArgumentNullException">Thrown if propertyName is null or an empty string.</exception>
        /// <exception cref="AggregateException">Thrown if any handlers raise exceptions, with the exceptions raised captured in the <see cref="AggregateException.InnerExceptions"/> property.</exception>
        public static void SafeRaise(this PropertyChangingEventHandler handler, INotifyPropertyChanging sender, string propertyName)
        {
            propertyName.ThrowIfNullOrEmpty(nameof(propertyName));
            sender?.GetType().ValidatePropertyName(propertyName, nameof(propertyName));

            if (handler is null)
            {
                return;
            }

            PropertyChangingEventArgs e = new (propertyName);
            List <Exception>          raisedExceptions = null;

            foreach (Delegate del in handler.GetInvocationList())
            {
                try
                {
                    del.DynamicInvoke(sender, e);
                }
                catch (TargetInvocationException ex) when(ex.InnerException is Exception)
                {
                    if (raisedExceptions is null)
                    {
                        raisedExceptions = new List <Exception>();
                    }

                    raisedExceptions.Add(ex.InnerException);
                }
            }

            // Check list of exceptions is either still null, or not empty.
            Debug.Assert(raisedExceptions is null || raisedExceptions.Any(), "Empty list of exceptions after handling event.");
            if (raisedExceptions is List <Exception> )
            {
                throw new AggregateException(Properties.Resources.SafeRaiseExceptionMessage, raisedExceptions);
            }
        }