2011-03-25 58 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

相关问题