c# - 将职责委派给 WinForm 控件——控件是否应该了解彼此的操作?

标签 c# winforms event-handling

我在表单上有一些控件:

  • 一个复选框,负责根据选中状态启用/禁用页面上的所有其他控件。
  • 一些单选按钮,负责根据选中状态启用/禁用页面上的特定控件。
  • 由上述控件操作的其他控件。

出现了几种情况:

  • 当表单初始化时,我加载复选框的状态。然后,它启用或禁用表单上的其余控件。
  • 随着表单继续初始化,我加载了单选按钮的状态。如果单选按钮被选中但被禁用,这有机会撤销之前的要求。因此,我先检查以确保单选按钮已启用。
  • 加载表单后,用户可以选中或取消选中单选按钮。这是一个微不足道的案例,我只是运行了满足最后一个要求的代码。但是,另一种情况是用户可以选中/取消选中该复选框。当复选框启用时,它想要重新启用页面上的所有控件,因为它禁用了它们。不过,这样做会违反单选按钮的要求。

这种情况用蛮力处理是微不足道的。我创建了几种方法来突出显示:

private void ChkBxSnmPv3OnCheckedChanged(object sender, EventArgs eventArgs)
{
    snmpSettingsErrorProvider.Clear();

    foreach (Control control in grpBxSNMPv3.Controls)
    {
        if (control != sender)
            control.Enabled = ((CheckBox)sender).Checked;
    }
}

private void rdBtnAuthNoPriv_CheckedChanged(object sender, EventArgs e)
{
    RadioButton authNoPrivRadioButton = ((RadioButton)sender);

    if (authNoPrivRadioButton.Enabled)
    {
        bool isChecked = authNoPrivRadioButton.Checked;

        SetControlState(cmbBxAuthProtocol, isChecked);
        SetControlState(mskdTxtBxAuthPassword, isChecked);
        SetControlState(mskdTxtBxAuthPasswordConfirm, isChecked);

        SetControlState(cmbBxPrivacyProtocol, !isChecked);
        SetControlState(mskdTxtBxPrivacyPassword, !isChecked);
        SetControlState(mskdTxtBxPrivacyPasswordConfirm, !isChecked);
    }
}
//More methods for other checkedChange and also for when rdBtn's enable.

布局的大概思路:

enter image description here

综上所述,我的问题很“简单”:

  • 方法应该在没有其他方法存在的假设下起作用。然而,如果我保留 rdBtn 对 chkBx 存在的逻辑判断,那么我将拥有必须相互对抗的代码。

我可以这样写我的代码:

private void ChkBxSnmPv3OnCheckedChanged(object sender, EventArgs eventArgs)
{
    snmpSettingsErrorProvider.Clear();

    txtBxEngineID = ((CheckBox)sender).Checked;
    rdBtnAuthNoPriv = ((CheckBox)sender).Checked;
    rdBtnAuthPriv = ((CheckBox)sender).Checked;
    rdBtnNoAuthNoPriv = ((CheckBox)sender).Checked;

    //Pass work for enabling Auth and Priv fields to rdBtn events.
}

此解决方案效率更高,并保证我不会看到任何闪烁。然而,这也意味着为了“成功完成”启用页面上的所有控件,我的 chkBx 现在必须依赖 rdBtn 的逻辑。这是好的编程习惯吗?

最佳答案

我认为这是保留在表单中的合理代码,但我会提出一些建议;

1) 强制转换的处理成本很小,因此您应该避免在循环内强制转换。事实上,作为一般概念,当结果保证保持不变时,您应该避免在循环内执行任何重复操作。所以你可以像这样改进你的第一个方法;

private void ChkBxSnmPv3OnCheckedChanged(object sender, EventArgs eventArgs)
{
    snmpSettingsErrorProvider.Clear();

    // cast the sender once only
    CheckBox cb = sender as CheckBox;
    if (null == cb) return;

    foreach (Control control in grpBxSNMPv3.Controls)
    {
        if (control != sender)
            control.Enabled = cb.Checked;
    }
}

2) 我建议将启用/禁用逻辑移出到一个单独的方法中,然后从您的控件事件处理程序中调用它。如果您决定从其他控件重用相同的逻辑,这将使您能够重用。紧密耦合行为以控制事件,我发现会导致重复代码。像这样;

private void ChkBxSnmPv3OnCheckedChanged(object sender, EventArgs eventArgs)
{
    snmpSettingsErrorProvider.Clear();

    // cast the sender once only
    CheckBox cb = sender as CheckBox;
    if (null == cb) return;

    SetEnabled(grpBxSNMPv3, cb.Checked, new[] { cb });
}

private void SetEnabled(Control parent, bool isEnabled, Control[] exludeControls)
{
    if (null == parent) return;

    foreach (Control control in parent.Controls)
    {
        if (!excludeControls.Contains(control))
            control.Enabled = isEnabled;
    }
}

您现在有一个可重用的方法来启用/禁用另一个包含的所有控件。

3) 关于您的最后一个问题,是的,我认为这种方法很好。减少耦合总是一件好事。想想如何设计您的方法以提高可重用性,我认为您会想出一个干净的解决方案。

关于c# - 将职责委派给 WinForm 控件——控件是否应该了解彼此的操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10690010/

相关文章:

c# - 在 C# 中将列表列表作为类使用

c# - 设置 DataGridView ComboBox 的默认值

c# - 如果 Rx 触发另一个事件,则忽略事件

authentication - 如何在 Symfony2 中监听 “remember me” 重新验证事件?

c# - 将 ASP.NET Web 窗体应用程序转换为桌面应用程序

c# - 在列表中跟踪分数以及姓名

c# - 如何设置 ToolStripMenuItem 在代码中可见?

javascript - D3 变焦设置

c# - 如何在全局平台卡外存储库上设置 key ?

c# - Emgu (OpenCV for C#) - 使用 cvStereoRectify 构建视差图