2012-05-21 30 views
3

我的控件的窗體上了一把:將責任委託給WinForm控件 - 控件應該知道對方的行爲?

  • 複選框負責啓用/禁用基於其選中狀態頁面上的所有其他控件。
  • 幾個單選按鈕,其負責啓用/根據自己的檢查狀態頁面上禁用特定的控制。
  • 其通過上述控制操作的其他控件。

幾個方案中可能出現:

  • 當表單初始化,我加載複選框的狀態。然後,它啓用或禁用窗體上的其他控件。
  • 作爲形式繼續初始化,我加載單選按鈕的狀態。如果單選按鈕被選中但被禁用,這有機會撤銷先前的要求。因此,我檢查以確保首先啓用單選按鈕。形式加載
  • 之後,用戶可以選擇或取消選擇的單選按鈕。這是一個微不足道的例子,我只是運行符合最後要求的代碼。另一種情況是,用戶可以選中/取消選中複選框。當複選框變爲啓用時,它希望重新啓用頁面上的所有控件,因爲它禁用了它們。但是,這樣做會破壞單選按鈕的要求。

這種情況是相當瑣碎與蠻力來處理。我創建了幾個方法來突出:

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的邏輯。這是不錯的編程習慣嗎?

+0

這個問題沒有多大意義,這些已經存在於* form *中的代碼片段。或者UserControl,不知道。沒有代碼在控件類中。這是事件的全部內容,讓某種*其他代碼知道發生了一些有趣的事情。這個代碼非常屬於這種形式,它是唯一知道它所託管的控件集合的任何類。 –

+0

嘿,對不起。我同意 - 我最初的帖子沒有足夠的意義。今天我會編輯它,當我有一點時間讓它更容易理解爲傳統目的。不過,我很困惑你的第二點。如果涉及單個課程的情況下不會使用事件,那麼呢?你有閱讀我支持嗎?代碼位於加載到表單上的用戶控件上。 –

回答

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; 
    } 
} 
1

我認爲這是明智的代碼,以保持形式,但我會提出一些建議;

1)鑄件的加工成本很小,所以你應該避免在一個循環內鑄造。事實上,作爲一般概念,當結果保證保持不變時,應該避免在循環內執行任何重複操作。所以你可以像這樣改進你的第一種方法; 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)關於你最後的問題,是的,我認爲這種方法沒問題。減少耦合總是一件好事。想想如何設計你的方法更加可重用,我想你會想出一個乾淨的解決方案。

+0

+1的建議。事實上,在更新我的主題之前,我確實遵循了所有這些建議 - 所以偉大的思想家都會這麼想。我繼續爲未來的人發佈一個乾淨的解決方案。讓我知道你是否看到任何可憐的東西。 :) –

相關問題