我正在构建一个Form,它有几个numericUpDown控件,几个复选框控件和一些文本框等。每个控件都有一个触发的事件方法(CheckedChanged,ValueChanged等),但我的主要问题是:
我想要做的是运行一个方法来更新表单上的文本字段,但目前我只重复了24次。这有效,但我觉得必须有一个更好的方法......下面是我迄今为止所拥有的一个例子。
private void button3_Click(object sender, EventArgs e)
{
// Code Specific to the Buton3_Click
UpdateTextLabel();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// Code Specific to the checkBox1_CheckChanged
UpdateTextLabel();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// numericUpDown1 specific code ....
UpdateTextLabel();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// comboBox1 specific stuff ...
UpdateTextLabel();
}
// .... and so on for every method ....
有没有更好的方法来实现这一目标?我想说“如果任何控件被点击或更改......请执行此操作”UpdateTextLabel()“事情”,但不知道如何去做。很高兴被引导到答案,因为我在搜索中输入的问题似乎不是“正确的问题”......
谢谢!
答案 0 :(得分:2)
当然!您可以使用lambdas轻松处理未使用的参数:
button3.Click += (sender, args) => UpdateTextLabel();
checkBox1.CheckedChanged += (sender, args) => UpdateTextLabel();
numericUpDown1.ValueChanged += (sender, args) => UpdateTextLabel();
comboBox1.SelectedIndexChanged += (sender, args) => UpdateTextLabel();
或者正如一些开发人员的趋势,如果你不关心args,你可以使用下划线“忽略”它们的可读性:
button3.Click += (_, __) => UpdateTextLabel();
checkBox1.CheckedChanged += (_, __) => UpdateTextLabel();
numericUpDown1.ValueChanged += (_, __) => UpdateTextLabel();
comboBox1.SelectedIndexChanged += (_, __) => UpdateTextLabel();
正如强大的Jon Skeet曾经训练过我,这远远优于CONTROLNAME_EVENTNAME的默认Visual Studio命名方案,因为您可以轻松阅读“单击按钮3时,更新文本标签”或“组合框更改时” ,更新文本标签“。它还释放了你的代码文件,以消除一堆无用的方法包装器。 :)
编辑:如果你重复了24次,从设计的角度来看,这似乎有点奇怪。 ... 再次读取哦。我错过了评论,您想要运行特定代码以及更新文本框。好吧,你可以注册多个事件:button3.Click += (_, __) => SubmitForm();
button3.Click += (_, __) => UpdateTextLabel();
问题在于技术上,事件监听器无法保证按顺序触发。但是,在这种简单的情况下(特别是如果您不使用-=
并组合事件处理程序),您应该可以维护执行顺序。 (我假设您需要UpdateTextLabel
在 SubmitForm
之后解雇
或者您可以将UpdateTextLabel
调用移动到按钮处理程序中:
button3.Click += (_, __) => SubmitForm();
private void SubmitForm(object sender, EventArgs e)
{
//do submission stuff
UpdateTextLabel();
}
哪种方式可以让你进入同一条船(尽管有更好的方法命名)。也许您应该将UpdateTextLabel
移动到您的表单的一般“重新绑定”:
button3.Click += (_, __) => SubmitForm();
private void SubmitForm(object sender, EventArgs e)
{
//do submission stuff
Rebind();
}
private void Rebind()
{
GatherInfo();
UpdateTextLabel();
UpdateTitles();
}
这样,如果除了更新文本标签之外还需要做其他工作,那么所有代码都会调用一般Rebind
(或任何你想要调用的内容),并且更容易更新。
EDITx2:我意识到,另一种选择是使用面向方面编程。使用像PostSharp这样的东西你可以装饰方法来执行编译的特殊代码。我99%肯定PostSharp允许你附加到事件(虽然我从来没有专门做过):
button3.Click += (_, __) => SubmitForm();
[RebindForm]
private void SubmitForm(object sender, EventArgs e)
{
//do submission stuff
}
[Serializable]
public class RebindFormAttribute : OnMethodBoundaryAspect
{
public override void OnSuccess( MethodExecutionArgs args )
{
MyForm form = args.InstanceTarget as MyForm; //I actually forgot the "InstanceTarget" syntax off the top of my head, but something like that is there
if (form != null)
{
form.Rebind();
}
}
}
因此,即使我们没有明确地在Rebind()
的任何地方进行调用,只要成功调用该方法,属性和面向方面编程最终会在那里运行额外的代码OnSuccess
。
答案 1 :(得分:2)
是的,任何控件的任何事件都可以共享相同的事件处理程序方法,只要它们的事件处理程序委托是相同的,在这种情况下,这些控件的事件处理程序委托都是“EventHandler”类型(没有返回值)和2个参数:object sender和EventArgs e)。
private void UpdateTextLabel(object sender, EventArgs e)
{
//your original UpdateTextLabel code here
}
button3.Click += UpdateTextLabel;
checkBox1.CheckedChanged += UpdateTextLabel;
numericUpDown1.ValueChanged += UpdateTextLabel;
comboBox1.SelectedIndexChanged += UpdateTextLabel;
答案 2 :(得分:0)
是的,你不想写这样的代码。您不必,Application.Idle事件是更新UI状态的理想选择。它在Winforms从消息队列中检索所有待处理消息后每次运行。因此可以保证在您当前订阅的任何事件之后运行。看起来像这样:
public Form1() {
InitializeComponent();
Application.Idle += UpdateTextLabel;
this.FormClosed += delegate { Application.Idle -= UpdateTextLabel; };
}
void UpdateTextLabel(object sender, EventArgs e) {
// etc..
}