简体   繁体   中英

Add Validating event handler in constructor of a custom TextBox control

I created a custom control that inherits from TextBox.

I have a ValidateTextBoxEntry method that is called by the Validating event.

Normally, I would use the Property editor in the visual editor to add ValidateTextBoxEntry to the Validating event of each and every instance of the custom control.

Instead, I would rather add a line in the constructor of the custom control to all the event handler automatically, something like this:

    public CustomTextBox()
    {
        InitializeComponent();
        this.Validating += 
        new System.ComponentModel.CancelEventHandler(ValidateTextBoxEntry);
   }

What is an elegant way of adding a Validating event handler to all instances of a custom control?

    this.Validating += 
    new System.ComponentModel.CancelEventHandler(ValidateTextBoxEntry);

This is not elegant. Events in .NET are an implementation of the Observer Pattern. You expose them so other code can subscribe the event and, in this case, customize the validation. It doesn't make sense to have to listen to your own events.

To accommodate, every Xxxx event has an OnXxxx() method. You can call this method yourself to cause the Validating event to be raised. Or, more commonly in this case, you leave it up to Winforms to call it for you. A sample implementation could look like this:

    protected override void OnValidating(CancelEventArgs e) {
        if (this.Text.Length == 0) e.Cancel = true;
        else base.OnValidating(e);
        DisplayWarning(e.Cancel);
    }

Note how the event handling is customized here. It implements the rule that it is never valid to have an empty string in the textbox. At which point there is no reason anymore to call base.Onvalidating(), you don't want an event handler to override that rule. And further extended by automatically taking care of displaying a hint to the user that his data-entry needs to be worked on.

Doing it this way gives you control over the order in which code runs, that can be very important.

I agree with elgonzo in the comments that this probably isn't the correct approach but I think you could achieve it with an interface .

If you define an interface that contains the handler definition and make each form implement that interface you can then wire the handler up from within the control if you can find the right form. For that you can keep iterating around the Parent property until it's null. I really don't think it's worth the effort though:

//the interface
public interface IShouldntDoThis
{
    void MyTextBox_Validating(object sender, CancelEventArgs e);
}

//the control
public class MyTextBox : TextBox
{
    public MyTextBox()
    {

    }

    protected override void InitLayout()
    {
        base.InitLayout();

        Control parent = this.Parent;
        while (parent.Parent != null)
        {
            parent = parent.Parent;
        }

        //parent should now be the Form
        IShouldntDoThis test = parent as IShouldntDoThis;
        if (test != null)
        {
            this.Validating += test.MyTextBox_Validating;
        }
    }
}

//the form
public partial class MainForm : Form, IShouldntDoThis
{
    public Form1()
    {
        InitializeComponent();
    }

    public void MyTextBox_Validating(object sender, CancelEventArgs e)
    {
        throw new NotImplementedException();
    }
}

Well, as it turns out, adding a line in the constructor (as I showed in the question), is the right approach (as stated by elgonzo - thank you).

The key is to make the event handler be a method of the class itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM