3

我在表单上有一些控件:

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

出现了几种情况:

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

用蛮力处理这种情况非常简单。我创建了几种方法来突出显示:

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.

粗略的布局思路:

在此处输入图像描述

尽管如此,我的问题很“简单”:

  • 方法应该在不假设存在其他方法的情况下工作。然而,如果我保留 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 的逻辑。这是良好的编程习惯吗?

4

2 回答 2

1

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

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)关于你的最后一个问题,是的,我认为这种方法很好。减少耦合总是一件好事。想想如何设计你的方法更可重用,我想你会想出一个干净的解决方案。

于 2012-05-21T22:28:36.013 回答
0

这就是我最终的结果。除了我正在初始化的两个列表之外,我对此非常满意。他们可能应该在他们自己的控制之下,但我还不能让自己做到这一点。

public partial class DeviceSnmpSettings : UserControl, INotifyPropertyChanged
{
    private readonly List<Control> AuthenticationControls = new List<Control>(6);
    private readonly List<Control> PrivacyControls = new List<Control>(6);
    public event PropertyChangedEventHandler PropertyChanged;

    public DeviceSnmpSettings()
    {
        InitializeComponent();
        InitializeAuthControls();
        InitializePrivacyControls();
    }

    public DeviceSnmpSettings(Point location)
        : this()
    {
        Location = location;
    }

    //TODO: Move out into sub-user control?
    private void InitializeAuthControls()
    {
        AuthenticationControls.Add(lblAuthPassword);
        AuthenticationControls.Add(mskdTxtBxAuthPassword);
        AuthenticationControls.Add(lblAuthProtocol);
        AuthenticationControls.Add(cmbBxAuthProtocol);
        AuthenticationControls.Add(lblAuthPasswordConfirm);
        AuthenticationControls.Add(mskdTxtBxAuthPasswordConfirm);
    }
    //TODO: Move out into sub-user control?
    private void InitializePrivacyControls()
    {
        PrivacyControls.Add(lblPrivacyPassword);
        PrivacyControls.Add(mskdTxtBxPrivacyPassword);
        PrivacyControls.Add(lblPrivacyProtocol);
        PrivacyControls.Add(cmbBxPrivacyProtocol);
        PrivacyControls.Add(lblPrivacyPasswordConfirm);
        PrivacyControls.Add(mskdTxtBxPrivacyPasswordConfirm);
    }

    private bool SNMPv3Enabled
    {
        get { return chkBxSNMPv3.Checked; }
        set { chkBxSNMPv3.Checked = value; }
    }

    private SNMPV3Mode SecurityMode
    {
        get
        {
            SNMPV3Mode mode = SNMPV3Mode.NoAuthNoPriv;

            if (rdBtnAuthNoPriv.Checked)
                mode = SNMPV3Mode.AuthNoPriv;
            else if(rdBtnAuthPriv.Checked)
                mode = SNMPV3Mode.AuthPriv;

            return mode;
        }
        set
        {
            switch (value)
            {
                case SNMPV3Mode.NoAuthNoPriv:
                    rdBtnNoAuthNoPriv.Checked = true;
                    break;
                case SNMPV3Mode.AuthNoPriv:
                    rdBtnAuthNoPriv.Checked = true;
                    break;
                default:
                    rdBtnAuthPriv.Checked = true;
                    break;
            }

            OnSecurityModeChanged();
        }
    }

    protected virtual void OnSecurityModeChanged()
    {
        AuthenticationControls.ForEach(control => SetControlEnabledState(control, AuthenticationEnabled));
        PrivacyControls.ForEach(control => SetControlEnabledState(control, PrivacyEnabled));
        NotifyPropertyChanged("SecurityMode");
    }

    private void NotifyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    private bool AuthenticationEnabled
    {
        get
        {
            return SNMPv3Enabled && (SecurityMode == SNMPV3Mode.AuthPriv || SecurityMode == SNMPV3Mode.AuthNoPriv);
        }
    }

    private bool PrivacyEnabled
    {
        get { return SNMPv3Enabled && SecurityMode == SNMPV3Mode.AuthPriv; }
    }

    private void ChkBxSnmPv3OnCheckedChanged(object sender, EventArgs eventArgs)
    {
        SetControlEnabledStates();
    }

    private void SetControlEnabledStates()
    {
        snmpSettingsErrorProvider.Clear();

        foreach (Control control in grpBxSNMPv3.Controls)
        {
            //Check each of the lists for the control to prevent flickering.
            if (control != chkBxSNMPv3 && !AuthenticationControls.Contains(control) && !PrivacyControls.Contains(control))
                control.Enabled = SNMPv3Enabled;
        }

        //Need to validate that our radio button's checked state is reflected properly.
        AuthenticationControls.ForEach(control => SetControlEnabledState(control, AuthenticationEnabled));
        PrivacyControls.ForEach(control => SetControlEnabledState(control, PrivacyEnabled));
    }

    public void LoadFields(NetworkDiscovery networkDiscovery)
    {
        SNMPv3Enabled = networkDiscovery.Snmpv3Enabled;
        SecurityMode = networkDiscovery.SecurityMode;
        txtBxSNMPv3Username.Text = networkDiscovery.Username;
        mskdTxtBxAuthPassword.Text = networkDiscovery.AuthPassword;
        mskdTxtBxAuthPasswordConfirm.Text = networkDiscovery.AuthPassword;
        cmbBxAuthProtocol.SelectedItem = networkDiscovery.AuthProtocol.ToString();
        mskdTxtBxPrivacyPassword.Text = networkDiscovery.PrivacyPassword;
        mskdTxtBxPrivacyPasswordConfirm.Text = networkDiscovery.PrivacyPassword;
        cmbBxPrivacyProtocol.SelectedItem = networkDiscovery.PrivacyProtocol.ToString();

        SetControlEnabledStates();
    }

    private void SetControlEnabledState(Control control, bool enabled)
    {
        control.Enabled = enabled;
                    //Clear errors set on errorProvider when control is disabled.
        if (!control.Enabled)
            snmpSettingsErrorProvider.SetError(control, string.Empty);
    }

    private void rdBtnNoAuthNoPriv_CheckedChanged(object sender, EventArgs e)
    {
        if (((RadioButton)sender).Checked)
            SecurityMode = SNMPV3Mode.NoAuthNoPriv;
    }

    private void rdBtnAuthNoPriv_CheckedChanged(object sender, EventArgs e)
    {
        if (((RadioButton)sender).Checked)
            SecurityMode = SNMPV3Mode.AuthNoPriv;
    }

    private void rdBtnAuthPriv_CheckedChanged(object sender, EventArgs e)
    {
        if (((RadioButton)sender).Checked)
            SecurityMode = SNMPV3Mode.AuthPriv;
    }
}
于 2012-05-21T22:51:52.223 回答