using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace Umbraco.Core.Events { /// /// Represents event data for events that support cancellation. /// public class CancellableEventArgs : EventArgs, IEquatable { private bool _cancel; private IDictionary _eventState; private static readonly ReadOnlyDictionary EmptyAdditionalData = new ReadOnlyDictionary(new Dictionary()); public CancellableEventArgs(bool canCancel, EventMessages messages, IDictionary additionalData) { CanCancel = canCancel; Messages = messages; AdditionalData = new ReadOnlyDictionary(additionalData); } public CancellableEventArgs(bool canCancel, EventMessages eventMessages) { if (eventMessages == null) throw new ArgumentNullException("eventMessages"); CanCancel = canCancel; Messages = eventMessages; AdditionalData = EmptyAdditionalData; } public CancellableEventArgs(bool canCancel) { CanCancel = canCancel; //create a standalone messages Messages = new EventMessages(); AdditionalData = EmptyAdditionalData; } public CancellableEventArgs(EventMessages eventMessages) : this(true, eventMessages) { } public CancellableEventArgs() : this(true) { } /// /// Flag to determine if this instance will support being cancellable /// public bool CanCancel { get; set; } /// /// If this instance supports cancellation, this gets/sets the cancel value /// public bool Cancel { get { if (CanCancel == false) { throw new InvalidOperationException("This event argument class does not support canceling."); } return _cancel; } set { if (CanCancel == false) { throw new InvalidOperationException("This event argument class does not support canceling."); } _cancel = value; } } /// /// if this instance supports cancellation, this will set Cancel to true with an affiliated cancellation message /// /// public void CancelOperation(EventMessage cancelationMessage) { Cancel = true; cancelationMessage.IsDefaultEventMessage = true; Messages.Add(cancelationMessage); } /// /// Returns the EventMessages object which is used to add messages to the message collection for this event /// public EventMessages Messages { get; } /// /// In some cases raised evens might need to contain additional arbitrary readonly data which can be read by event subscribers /// /// /// This allows for a bit of flexibility in our event raising - it's not pretty but we need to maintain backwards compatibility /// so we cannot change the strongly typed nature for some events. /// public ReadOnlyDictionary AdditionalData { get; set; } /// /// This can be used by event subscribers to store state in the event args so they easily deal with custom state data between a starting ("ing") /// event and an ending ("ed") event /// public IDictionary EventState { get => _eventState ?? (_eventState = new Dictionary()); set => _eventState = value; } public bool Equals(CancellableEventArgs other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(AdditionalData, other.AdditionalData); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((CancellableEventArgs) obj); } public override int GetHashCode() { return AdditionalData != null ? AdditionalData.GetHashCode() : 0; } public static bool operator ==(CancellableEventArgs left, CancellableEventArgs right) { return Equals(left, right); } public static bool operator !=(CancellableEventArgs left, CancellableEventArgs right) { return Equals(left, right) == false; } } }