简体   繁体   English

在自定义TextBox控件的构造函数中添加Validating事件处理程序

[英]Add Validating event handler in constructor of a custom TextBox control

I created a custom control that inherits from TextBox. 我创建了一个继承自TextBox的自定义控件。

I have a ValidateTextBoxEntry method that is called by the Validating event. 我有一个ValidateTextBoxEntry方法,由Validating事件调用。

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. 通常,我会使用可视化编辑器中的属性编辑器将ValidateTextBoxEntry添加到自定义控件的每个实例的Validating事件中。

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? 将Validating事件处理程序添加到自定义控件的所有实例的优雅方法是什么?

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

This is not elegant. 这不优雅。 Events in .NET are an implementation of the Observer Pattern. .NET中的事件是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. 为了适应,每个Xxxx事件都有一个OnXxxx()方法。 You can call this method yourself to cause the Validating event to be raised. 您可以自己调用此方法以引发Validating事件。 Or, more commonly in this case, you leave it up to Winforms to call it for you. 或者,更常见的是,在这种情况下,您可以将其留给Winforms来为您调用它。 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. 此时没有理由再调用base.Onvalidating(),您不希望事件处理程序覆盖该规则。 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 . 我同意elgonzo的评论,这可能不是正确的方法,但我认为你可以通过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. 为此,您可以继续迭代Parent属性,直到它为空。 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). 好吧,事实证明,在构造函数中添加一行(正如我在问题中所示), 正确的方法(如elgonzo所述 - 谢谢)。

The key is to make the event handler be a method of the class itself. 关键是使事件处理程序成为类本身的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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