Search code examples
c#.netwinformseventsuser-controls

Overriden event not being called in user control


I have a usercontrol with a TextBox on it:

public partial class MyControl : UserControl
{
    public new event CancelEventHandler Validating
    {
        add
        {
            txt.Validating += value;
        }
        remove
        {
            txt.Validating -= value;
        }
    }

    public new string Text
    {
        get => txt.Text;
        set => txt.Text = value;
    }
}

I place the control and an ErrorProvider on a form and do the following:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        SetErrorEvents(myControl1);
    }

    private void SetErrorEvents(object control)
    {
        (control as Control).Validating += ValidationEvent;
    }

    private void ValidationEvent(object sender, CancelEventArgs e)
    {
        var control = (Control)sender;

        if (string.IsNullOrWhiteSpace(control.Text))
            errorProvider1.SetError(control, "error");
        else
            errorProvider1.SetError(control, string.Empty);
    }
}

When setting the delegate for the my control's Validating event, it's setting the delegate for the UserControl itself and not being overriden so that the event of the TextBox will be set.

Shouldn't the above work as is? What am I missing?


Solution

  • It's not overriden, it's been shadowed or hidden by new keyword. You haven't subscribed to the new event, you have subscribed for the base class event. It's basically how polymorphism works.

    • If you want to raise the Validating event of the user control when a child control is validating, handle Validating event of the child control and call OnValidating method of the user control.

    • If you want to override the Validating event override OnValidating method.

    • If you want to change the sender of Validating event, you need to change the way that Validating event has been invoked. To do so, you need to use reflection and find the event and directly invoke it yourself.

    Example - Raising Validating event of UserControl when Child control is validating

    If you like to raise Validating event of your control when the child text box is validating, handle Validating event of the child control and call ``

    public MyControl()
    {
        InitializeComponent();
        txt.Validating += (obj, args) => OnValidating(args);
    }
    

    Example - Override Validating Event

    protected override void OnValidating(CancelEventArgs e)
    {       
        // Add custom code here.       
        base.OnValidating(e);
    }
    

    Example - Raising Validating event manually without calling base.OnValidating

    If for some reason you don't want to call base.OnValidating, while its responsibility is basically raising the Validating event, you can find the event and invoke it directly:

    protected override void OnValidating(CancelEventArgs e)
    {  
        var f = typeof(Control).GetField("EventValidating",
                System.Reflection.BindingFlags.NonPublic |
                System.Reflection.BindingFlags.Static);
        var validating = (CancelEventHandler)Events[f.GetValue(this)];
        validating?.Invoke(this, e); 
    }
    

    Doing so, for example you can set another sender like the child control, instead of this.