Как реализовать проверку контроля в приложении Windows Forms? - PullRequest
3 голосов
/ 25 марта 2011

Я пытаюсь лучше понять, как проверка работает в приложении 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 , которое я задал вчера.

Ответы [ 2 ]

5 голосов
/ 25 марта 2011

Назначение свойства DialogResult - это то, что закрывает диалог.Он продолжает работать, пока он установлен на None.Вам не нужен звонок Close().Код, который вызывает ShowDialog(), получает значение DialogResult, которое вы назначили в качестве возвращаемого значения.Поэтому он знает, был ли диалог закрыт с помощью OK или просто отменен.

Также обратите внимание, что при написании обработчика события проверки вам не нужно ValidateChildren().Вы устанавливаете e.Cancel = true, чтобы пользователь не мог отойти от текстового поля.Это означает, что она может добраться до кнопки ОК только тогда, когда текстовое поле было проверено, чтобы быть в порядке.Однако вы должны убедиться, что элемент управления, который имеет проверку, выбирается первым, когда отображается диалоговое окно.

Дружественный диалог - это тот, в котором пользователь может свободно переключаться между элементами управления и выбирать «простые».,Теперь вам нужны две проверки: одна проверяет, является ли введенное значение действительным, другая проверяет, нет ли пропущенных значений.Вы получите это, приняв пустую строку в обработчике события Validation.Но последнее не очень хорошо поддерживается Winforms, вам нужен код.

2 голосов
/ 07 июня 2011

Я знаю, что уже несколько поздно, но я бы добавил еще одну вещь к ответу Ганса.Создайте событие текстового поля Validated и переместите 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, "");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...