我创建了一个继承自TextBox的自定义控件。
我有一个ValidateTextBoxEntry方法,由Validating事件调用。
通常,我会使用可视化编辑器中的属性编辑器将ValidateTextBoxEntry添加到自定义控件的每个实例的Validating事件中。
相反,我宁愿在自定义控件的构造函数中自动添加一行到所有事件处理程序,如下所示:
public CustomTextBox()
{
InitializeComponent();
this.Validating +=
new System.ComponentModel.CancelEventHandler(ValidateTextBoxEntry);
}
将Validating事件处理程序添加到自定义控件的所有实例的优雅方法是什么?
答案 0 :(得分:2)
this.Validating +=
new System.ComponentModel.CancelEventHandler(ValidateTextBoxEntry);
这不优雅。 .NET中的事件是Observer Pattern的一个实现。您公开它们,以便其他代码可以订阅该事件,在这种情况下,自定义验证。听取自己的活动是没有意义的。
为了适应,每个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(),您不希望事件处理程序覆盖该规则。并通过自动处理向用户显示他的数据输入需要处理的提示进一步扩展。
这样做可以让您控制代码运行的顺序,这非常重要。
答案 1 :(得分: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();
}
}
答案 2 :(得分:0)
好吧,事实证明,在构造函数中添加一行(正如我在问题中所示),是正确的方法(如elgonzo所述 - 谢谢)。
关键是要使事件处理程序成为类本身的方法。