2011-03-25 59 views
3

我想更好地瞭解驗證如何在Windows窗體應用程序中工作。互聯網充滿了微不足道的例子,但我找不到一個解釋控制驗證的非平凡例子。無論如何,感謝SwDevMan81Hans Passant我從一個比昨天好得多的地方開始。如何在Windows窗體應用程序中實現控件驗證?

「真正的應用程序」包含許多TextBox控件的對話框。每個控件都實現了Validating事件。正如您在示例中看到的,由於Click事件導致將驗證事件發送到每個控件,因此調用ValidateChildren。該應用程序還使用ErrorProvider控件來提供用戶反饋。昨天,我不明白如何使用確定按鈕Click事件來執行此驗證。今天,我的對話按預期工作。單擊確定按鈕會導致ErrorProvider執行控件無效並且對話框未意外關閉的事情。

所以,雖然這似乎工作,我仍然覺得,我「在線外」着色。在Windows Forms應用程序中是否有用於控制驗證的「最佳實踐」文檔/網站?

在仍然令我困惑的許多事情中,當Ok按鈕DialogResult屬性設置爲返回DialogResult.OK時,我無法找到對話框行爲的解釋。爲什麼設置這個屬性會影響驗證? (嘗試我的例子,有沒有這條線,看看我的意思。)

我昨天的問題(它會出現)大部分來自不理解ValidateChildren方法,並從我設置Ok按鈕DialogResult屬性爲DialogResult。好。將該屬性設置爲DialogResult.None似乎改變了Form類的一些自動行爲。

TIA

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 

namespace ConsoleApp 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Dialog dialog = new Dialog(); 

      if(dialog.ShowDialog() == DialogResult.OK) 
       Console.Beep(); 
     } 
    } 

    public class Dialog : Form 
    { 
     TextBox m_TextBox0; 
     TextBox m_TextBox1; // not validated 
     TextBox m_TextBox2; 

     Button m_OkBtn; 
     Button m_CancelBtn; 

     ErrorProvider m_ErrorProvider; 

     public Dialog() 
     { 
      m_TextBox0 = CreateTextBox(0, "TextBox 0"); 
      m_TextBox1 = CreateTextBox(1, "TextBox 1"); 
      m_TextBox2 = CreateTextBox(2, "TextBox 2"); 

      m_OkBtn  = CreateButton(3, "Ok"); 
      m_CancelBtn = CreateButton(4, "Cancel"); 

      m_ErrorProvider = new ErrorProvider(this); 

      //m_BtnOk.DialogResult = DialogResult.OK; 
      m_OkBtn.Click += new EventHandler(BtnOk_Click); 
      m_OkBtn.CausesValidation = true; 

      m_CancelBtn.DialogResult = DialogResult.Cancel; 
      m_CancelBtn.CausesValidation = false; 
     } 

     void BtnOk_Click(object sender, EventArgs e) 
     { 
      if(ValidateChildren()) 
      { 
       DialogResult = DialogResult.OK; 
       Close(); 
      } 
     } 

     void TextBox_Validating(object sender, CancelEventArgs e) 
     { 
      m_ErrorProvider.Clear(); 

      TextBox textBox = sender as TextBox; 

      // m_TextBox1 is always valid, the others are valid if they have text. 
      bool valid = textBox.TabIndex == 1 || textBox.Text.Length > 0; 

      if(!valid) 
       m_ErrorProvider.SetError(textBox, "Error " + textBox.Name); 

      e.Cancel = !valid; 
     } 

     Button CreateButton(int index, string name) 
     { 
      Button button = new Button(); 

      button.TabIndex = index; 
      button.Text = name; 
      button.Location = new System.Drawing.Point(0, index * 30); 

      Controls.Add(button); 

      return button; 
     } 

     TextBox CreateTextBox(int index, string name) 
     { 
      Label label = new Label(); 
      label.Text = name; 
      label.Location = new System.Drawing.Point(0, index * 30); 

      TextBox textBox = new TextBox(); 

      textBox.TabIndex = index; 
      textBox.CausesValidation = true; 
      textBox.Validating += new CancelEventHandler(TextBox_Validating); 
      textBox.Location = new System.Drawing.Point(100, index * 30); 

      Controls.Add(label); 
      Controls.Add(textBox); 

      return textBox; 
     } 
    } 
} 

編輯:這裏是最終的解決方案。我認爲它很容易使用,同時也滿足所有其他要求。我提前道歉這個問題結束了多久。如果我能向你展示所有真正的應用程序,那麼爲什麼這麼重要會更有意義。無論如何,感謝幫助這隻老狗學習了一個新的技巧。

答案是爲每個控制需要驗證一個ErrorProvider控件(對整個對話一個ErrorProvider控件。在此之後,這一切是相當簡單的。

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 

namespace ConsoleApp 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Dialog dialog = new Dialog(); 

      if(dialog.ShowDialog() == DialogResult.OK) 
       Console.Beep(); 
     } 
    } 

    public class CompositeControl 
    { 
     Label   m_Label; 
     TextBox  m_TextBox; 
     ErrorProvider m_ErrorProvider; 

     Dialog m_Dialog; 

     public CompositeControl(int index, string name, Dialog dialog) 
     { 
      m_Label = new Label(); 
      m_Label.Text = name; 
      m_Label.Location = new System.Drawing.Point(0, index * 30); 

      m_TextBox = new TextBox(); 

      m_TextBox.TabIndex = index; 
      m_TextBox.CausesValidation = true; 
      m_TextBox.Validating += new CancelEventHandler(TextBox_Validating); 
      m_TextBox.Location = new System.Drawing.Point(100, index * 30); 

      m_Dialog = dialog; 

      m_ErrorProvider = new ErrorProvider(m_Dialog); 

      m_Dialog.Controls.Add(m_Label); 
      m_Dialog.Controls.Add(m_TextBox); 
     } 

     void TextBox_Validating(object sender, CancelEventArgs e) 
     { 
      TextBox textBox = sender as TextBox; 

      if(!m_Dialog.IsClosing && textBox.Text.Length == 0) 
       return; 

      // m_TextBox1 is always valid, the others are valid if they have text. 
      bool valid = textBox.TabIndex == 1 || textBox.Text.Length > 0; 

      if(!valid) 
       m_ErrorProvider.SetError(textBox, "Error " + textBox.Name); 
      else 
       m_ErrorProvider.Clear(); 

      e.Cancel = !valid; 
     } 
    } 

    public class Dialog : Form 
    { 
     CompositeControl m_CompositeControl0; 
     CompositeControl m_CompositeControl1; // not validated 
     CompositeControl m_CompositeControl2; 

     Button m_OkBtn; 
     Button m_CancelBtn; 

     bool m_IsClosing = false; 

     public Dialog() 
     { 
      m_CompositeControl0 = new CompositeControl(0, "TextBox 0", this); 
      m_CompositeControl1 = new CompositeControl(1, "TextBox 1", this); 
      m_CompositeControl2 = new CompositeControl(2, "TextBox 2", this); 

      m_OkBtn  = CreateButton(3, "Ok"); 
      m_CancelBtn = CreateButton(4, "Cancel"); 

      //m_BtnOk.DialogResult = DialogResult.OK; 
      m_OkBtn.Click += new EventHandler(BtnOk_Click); 
      m_OkBtn.CausesValidation = true; 

      m_CancelBtn.DialogResult = DialogResult.Cancel; 
      m_CancelBtn.CausesValidation = false; 
     } 

     void BtnOk_Click(object sender, EventArgs e) 
     { 
      m_IsClosing = true; 

      if(ValidateChildren()) 
      { 
       DialogResult = DialogResult.OK; 
       Close(); 
      } 

      m_IsClosing = false; 
     } 

     Button CreateButton(int index, string name) 
     { 
      Button button = new Button(); 

      button.TabIndex = index; 
      button.Text = name; 
      button.Location = new System.Drawing.Point(0, index * 30); 

      Controls.Add(button); 

      return button; 
     } 

     public bool IsClosing { get { return m_IsClosing; } } 
    } 
} 

這個問題是一個跟進one我昨天問。

回答

5

分配DialogResult性質是什麼使一個對話框關閉。它使同時它設置爲None運行。你不需要Close()調用。調用ShowDialog()的代碼獲得了DialogResult值你分配爲返回值。所以它知道對話框是以「OK」還是「取消」關閉。

另請注意,您編寫驗證事件處理程序的方式不需要ValidateChildren()。您設置了e.Cancel = true以防止用戶離開文本框。這意味着當文本框被驗證爲可以時,她只能進入OK按鈕。但是,您必須確保在顯示對話框時首先選擇具有驗證的控件。

一個友好的對話是一個地方的用戶是免費的控件之間選項卡,並摘掉「難辦」。您現在需要兩個驗證,一個驗證輸入的值是否有效,另一個驗證是否沒有缺失值。您可以通過在Validation事件處理程序中接受一個空字符串來獲得此信息。但後者不能很好地支持Winforms,你需要代碼。

+0

先生們,謝謝你的幫助。 – 2011-03-28 19:48:03

+0

到e.Cancel分配真實並不總是防止焦點變化,特別是如果Form.Autovalidate == EnableAllowFocusChange。如果你想給操作者自由在其中爲了修復他的錯誤,點擊確定之前,像滾動的是有助於修復該錯誤眼簾 – 2017-09-12 14:06:29

2

我知道這是有點晚了,但我想補充一件事漢斯回答。創建一個文本框事件驗證並將m_ErrorProvider.Clear()移動到Validated事件。驗證完成時(e.cancel == false),驗證的事件被觸發。所以你會有這樣的事情:


void TextBox_Validating(object sender, CancelEventArgs e) { 
    TextBox textBox = sender as TextBox; 

    bool valid = textBox.TabIndex == 1 || textBox.Text.Length > 0; 

    if(!valid) 
     m_ErrorProvider.SetError(textBox, "Error " + textBox.Name); 

    e.Cancel = !valid; 
} 

private void TextBox_Validated(object sender, System.EventArgs e) { 
    TextBox textBox = sender as TextBox; 
    m_ErrorProvider.SetError(textBox, ""); 
} 
+0

尼斯信息,我喜歡它,這是經常被使用。 – 2011-06-08 13:18:59

相關問題