1

我创建了一个继承自 TextBox 的自定义控件。

我有一个由 Validating 事件调用的 ValidateTextBoxEntry 方法。

通常,我会使用可视化编辑器中的属性编辑器将 ValidateTextBoxEntry 添加到自定义控件的每个实例的 Validating 事件中。

相反,我宁愿在自定义控件的构造函数中自动向所有事件处理程序添加一行,如下所示:

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

将 Validating 事件处理程序添加到自定义控件的所有实例的优雅方法是什么?

4

3 回答 3

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

这并不优雅。.NET 中的事件是观察者模式的一种实现。您公开它们,以便其他代码可以订阅事件,在这种情况下,自定义验证。必须听自己的事件是没有意义的。

为了适应,每个 Xxxx 事件都有一个 OnXxxx() 方法。您可以自己调用此方法来引发 Validating 事件。或者,在这种情况下更常见的是,您让 Winforms 为您调用它。示例实现可能如下所示:

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

请注意如何在此处自定义事件处理。它实现了在文本框中有一个空字符串永远是无效的规则。此时没有理由再调用 base.Onvalidating(),您不希望事件处理程序覆盖该规则。并通过自动处理向用户显示需要处理他的数据输入的提示来进一步扩展。

这样做可以让您控制代码运行的顺序,这非常重要。

于 2014-08-05T21:45:41.507 回答
1

我同意 elgonzo 在评论中认为这可能不是正确的方法,但我认为您可以使用interface.

如果您定义了一个包含处理程序定义的接口并使每个表单都实现该接口,那么如果您能找到正确的表单,您就可以从控件中连接处理程序。为此,您可以继续围绕该Parent属性进行迭代,直到它为空。我真的不认为这是值得的努力:

//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();
    }
}
于 2014-08-04T22:14:43.093 回答
0

好吧,事实证明,在构造函数中添加一行(如我在问题中所示)正确的方法(如 elgonzo 所述 - 谢谢)。

关键是使事件处理程序成为类本身的方法。

于 2014-08-05T21:10:30.297 回答