March 5, 2010

The missing Generic CancelEventHandler<T> Delegate in the BCL

How to make an Generic implementation of an cancel event handler

/// <summary>
    /// Represents the method that handles a cancelable event.
    /// </summary>
    /// <typeparam name="TCancelEventArgs">The type specifier for the event.</typeparam>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">A CancelChangingEventArg&lt;T&gt; that contains the event data.</param>
    [Serializable]
    [System.Security.Permissions.HostProtection(System.Security.Permissions.SecurityAction.LinkDemand, SharedState = true)]
    public delegate void CancelEventHandler<TCancelEventArgs>(object sender, TCancelEventArgs e) where TCancelEventArgs : System.ComponentModel.CancelEventArgs;

    /// <summary>
    /// Provides data for a cancelable changing event.
    /// </summary>
    /// <typeparam name="T">The type of the property that is changing.</typeparam>
    public class CancelChangingEventArg<T> : System.ComponentModel.CancelEventArgs
    {
        private T cv = default(T);
        /// <summary>
        /// Gets the current value of a property as reported by a changing event.
        /// </summary>
        /// <returns>The generic value. In a practical implementation of the CancelChangingEventArg<T>, the generic type of this property is replaced with the constrained type of the implementation.</returns>
        [Description("Current value of a property")]
        public T CurrentValue
        {
            get { return cv; }
        }

        private T nv = default(T);
        /// <summary>
        /// Gets the new value of a property as reported by a changing event.
        /// </summary>
        /// <returns>The generic value. In a practical implementation of the CancelChangingEventArg<T>, the generic type of this property is replaced with the constrained type of the implementation.</returns>
        [Description("New value of a property")]
        public T NewValue
        {
            get { return nv; }
        }

        /// <summary>
        /// Initializes a new instance of the CancelChangingEventArg<T> class, with provided old and new values and the CancelChangingEventArg.Cancel property set to false.
        /// </summary>
        /// <param name="oldValue">Current value of the property at the time of the event.</param>
        /// <param name="newValue">New value of the property.</param>
        public CancelChangingEventArg(T currentValue, T newValue)
            : base()
        {
            cv = currentValue;
            nv = newValue;
        }

        /// <summary>
        /// Initializes a new instance of the CancelChangingEventArg<T> class, with provided old and new values and the CancelChangingEventArg.Cancel property set to the given value.
        /// </summary>
        /// <param name="oldValue">Current value of the property at the time of the event.</param>
        /// <param name="newValue">New value of the property.</param>
        /// <param name="cancel">true to cancel the event; otherwise, false.</param>
        public CancelChangingEventArg(T currentValue, T newValue, bool cancel)
            : base(cancel)
        {
            cv = currentValue;
            nv = newValue;
        }
    }
//Using the code: 
public class MyClass
{
    public event CancelEventHandler<CancelChangingEventArg<int>> SomePropertyChanging;

    private int _SomeProperty;    
    public int SomeProperty    
    {
        get { return _SomeProperty; }
        set { SetProperty(ref _SomeProperty, ref value); }
    }
    
    private void SetProperty(ref int property, ref int value)    
    {
        if (SomePropertyChanging != null)        
        {
            CancelChangingEventArg<int> ResponseArg = new CancelChangingEventArg<int>(property,value);
            SomePropertyChanging(this, ResponseArg);
            if (!ResponseArg.Cancel)
                property = value;        
        }
        else
            property = value;    
    }
    
    public MyClass()    
    {
        _SomeProperty = 10;    
    }

}

public class MyProgram
{
    MyClass myc = new MyClass();
    public MyProgram()    
    {
        myc.SomePropertyChanging += new CancelEventHandler<CancelChangingEventArg<int>>(myc_SomePropertyChanging);
        myc.SomeProperty = 9; //this will be canceled.
        myc.SomeProperty = 11; //this will be accepted, and the value of the SomeProperty is now 11.    
    }
    
    private void myc_SomePropertyChanging(object sender, CancelChangingEventArg<int> e)    
    {
        //here we say if the new value is smaller than the one already in, then cancel the operation.
        //else set the value.
        e.Cancel = (e.CurrentValue > e.NewValue);    
    }
}

Total Pageviews