Я пытаюсь лучше понять, как проверка работает в приложении Windows Forms. В интернете полно тривиальных примеров, но я не смог найти ни одного нетривиального примера, объясняющего валидацию управления. В любом случае, благодаря SwDevMan81 и Хансу Пассанту Я начинаю с гораздо лучшего места, чем вчера.
«Реальное приложение» имеет диалог со многими элементами управления TextBox. Каждый из элементов управления реализует событие Validating . Как видно из примера, ValidateChildren вызывается в результате события Click , вызывающего отправку события Validating каждому из элементов управления. Приложение также использует элемент управления ErrorProvider , чтобы предоставить обратную связь с пользователем. Вчера я не понял, как использовать событие нажатия кнопки «ОК» для выполнения этой проверки. Сегодня мой диалог работает как положено. Нажатие кнопки ОК заставляет ErrorProvider выполнять свою функцию, когда элемент управления недопустим и диалоговое окно неожиданно не закрывается.
Так что, хотя это, похоже, работает, у меня остается ощущение, что я "раскрашивался за пределы линий". Существует ли документ / сайт с «наилучшей практикой» для проверки элементов управления в приложении Windows Forms?
Из многих вещей, которые все еще смущают меня, я не могу найти объяснение поведения моего диалога, когда свойство кнопки DialogResult установлено для возврата DialogResult.OK . Почему установка этого свойства мешает проверке? (Попробуйте мой пример с этой строкой и без нее, чтобы понять, что я имею в виду.)
Мои проблемы со вчерашнего дня (казалось бы) возникли в основном из-за непонимания метода ValidateChildren и из-за того, что я установил свойство DialogResult кнопки Ok для DialogResult.OK. Установка этого свойства в DialogResult. Похоже, что ни одно из них не меняет автоматического поведения класса Form.
ТИА
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 , которое я задал вчера.