3

我正在构建一个表单,它有几个 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()”操作”,但不知道该怎么做。很高兴被引导到答案,因为我在搜索中输入的问题似乎不是“正确的问题”......

谢谢!

4

3 回答 3

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

于 2012-07-02T12:41:23.243 回答
2

是的,任何控件的任何事件都可以共享相同的事件处理程序方法,只要它们的事件处理程序委托相同,在这种情况下,这些控件的事件处理程序委托都是“EventHandler”类型(无返回值和 2 个参数) : 对象发送者和 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;
于 2012-07-02T12:57:45.987 回答
0

是的,您不想编写这样的代码。您不必这样做,Application.Idle 事件是更新 UI 状态的理想选择。它每次在 Winforms 从消息队列中检索到所有待处理消息后运行。所以保证在您当前订阅的任何事件之后运行。让它看起来像这样:

    public Form1() {
        InitializeComponent();
        Application.Idle += UpdateTextLabel;
        this.FormClosed += delegate { Application.Idle -= UpdateTextLabel; };
    }

    void UpdateTextLabel(object sender, EventArgs e) {
        // etc..
    }
于 2012-07-02T12:54:40.317 回答