WinForm UI验证

Ref*_*din 43 .net c# validation user-interface winforms

我需要在整个winform应用程序中实现输入验证.有许多不同的形式可以输入数据,我希望不通过表单控制来控制每个项目创建isValid等.别人怎么处理这个?

我看到大多数相关帖子都涉及Web应用程序和/或提及企业库验证应用程序块.现在我承认我还没有彻底研究过ELVAB,但对于我需要的东西来说似乎有些过分.我目前的想法是编写一个具有各种要求的类库,并将控件作为参数传递给它.我已经有了一个RegEx函数库,用于像isValidZipCode这样的东西,所以这可能是我开始的地方.

我想要的是一个验证按钮,onClick循环遍历该表单页面上的所有控件并执行所需的验证.我怎么能做到这一点?

Mat*_*ell 63

验证已内置到WinForms库中.

每个Control派生的对象都有两个名为Validating和的事件Validated.它还有一个叫做的属性CausesValidation.当此设置为true(默认情况下为true)时,控件将参与验证.否则,它没有.

验证作为焦点的一部分发生.当您关注控件时,会触发其验证事件.事实上,焦点事件是按特定顺序触发的.来自MSDN:

通过使用键盘(TAB,SHIFT + TAB等)更改焦点,通过调用Select或SelectNextControl方法,或通过将ContainerControl .. ::.ActiveControl属性设置为当前窗体,焦点事件发生在以下顺序:

  1. 输入
  2. 的GotFocus
  3. 离开
  4. 证实
  5. 验证
  6. 引发LostFocus

使用鼠标或通过调用Focus方法更改焦点时,焦点事件按以下顺序发生:

  1. 输入
  2. 的GotFocus
  3. 引发LostFocus
  4. 离开
  5. 证实
  6. 验证

如果CausesValidation属性设置为false,则抑制Validating和Validated事件.

如果在Validating事件委托中将CancelEventArgs的Cancel属性设置为true,则会禁止在Validating事件之后通常发生的所有事件.

此外,ContainerControl有一个方法ValidateChildren(),它将循环包含的控件并验证它们.


Bru*_*uce 43

我意识到这个线程很老了,但我想我会发布我想出的解决方案.

在WinForms上验证的最大问题是验证仅在控件"失去焦点"时执行.因此,用户必须实际单击文本框内部,然后单击其他位置以执行验证例程.如果您只关心输入的数据是正确的,那么这很好.但是,如果您尝试确保用户没有通过跳过它而将文本框留空,那么这不会很好.

在我的解决方案中,当用户单击表单的提交按钮时,我检查表单上的每个控件(或指定的任何容器)并使用反射来确定是否为控件定义了验证方法.如果是,则执行验证方法.如果任何验证失败,则例程返回失败并允许该过程停止.如果您有多个表单需要验证,此解决方案效果很好.

1)只需将此部分代码复制并粘贴到您的项目中即可.我们正在使用Reflection,因此您需要将System.Reflection添加到using语句中

class Validation
{
    public static bool hasValidationErrors(System.Windows.Forms.Control.ControlCollection controls)
    {
        bool hasError = false;

        // Now we need to loop through the controls and deterime if any of them have errors
        foreach (Control control in controls)
        {
            // check the control and see what it returns
            bool validControl = IsValid(control);
            // If it's not valid then set the flag and keep going.  We want to get through all
            // the validators so they will display on the screen if errorProviders were used.
            if (!validControl)
                hasError = true;

            // If its a container control then it may have children that need to be checked
            if (control.HasChildren)
            {
                if (hasValidationErrors(control.Controls))
                    hasError = true;
            }
        }
        return hasError;
    }

    // Here, let's determine if the control has a validating method attached to it
    // and if it does, let's execute it and return the result
    private static bool IsValid(object eventSource)
    {
        string name = "EventValidating";

        Type targetType = eventSource.GetType();

        do
        {
            FieldInfo[] fields = targetType.GetFields(
                 BindingFlags.Static |
                 BindingFlags.Instance |
                 BindingFlags.NonPublic);

            foreach (FieldInfo field in fields)
            {
                if (field.Name == name)
                {
                    EventHandlerList eventHandlers = ((EventHandlerList)(eventSource.GetType().GetProperty("Events",
                        (BindingFlags.FlattenHierarchy |
                        (BindingFlags.NonPublic | BindingFlags.Instance))).GetValue(eventSource, null)));

                    Delegate d = eventHandlers[field.GetValue(eventSource)];

                    if ((!(d == null)))
                    {
                        Delegate[] subscribers = d.GetInvocationList();

                        // ok we found the validation event,  let's get the event method and call it
                        foreach (Delegate d1 in subscribers)
                        {
                            // create the parameters
                            object sender = eventSource;
                            CancelEventArgs eventArgs = new CancelEventArgs();
                            eventArgs.Cancel = false;
                            object[] parameters = new object[2];
                            parameters[0] = sender;
                            parameters[1] = eventArgs;
                            // call the method
                            d1.DynamicInvoke(parameters);
                            // if the validation failed we need to return that failure
                            if (eventArgs.Cancel)
                                return false;
                            else
                                return true;
                        }
                    }
                }
            }

            targetType = targetType.BaseType;

        } while (targetType != null);

        return true;
    }

}
Run Code Online (Sandbox Code Playgroud)

2)对要验证的任何控件使用标准验证事件. 当验证失败时,务必使用e.Cancel!

private void txtLastName_Validating(object sender, CancelEventArgs e)
    {
        if (txtLastName.Text.Trim() == String.Empty)
        {
            errorProvider1.SetError(txtLastName, "Last Name is Required");
            e.Cancel = true;
        }
        else
            errorProvider1.SetError(txtLastName, "");
    }
Run Code Online (Sandbox Code Playgroud)

3)不要跳过这一步!窗体上的AutoValidate属性设置为EnableAllowFocusChange.即使验证失败,这也允许对另一个控件进行制表.

4)最后,在Submit Button方法中,调用Validation方法并指定要检查的容器.它可以是整个表单,也可以是表单上的容器,如Panel或Group.

private void btnSubmit_Click(object sender, EventArgs e)
    {
        // the controls collection can be the whole form or just a panel or group
        if (Validation.hasValidationErrors(frmMain.Controls))
            return;

        // if we get here the validation passed
        this.close();
    }
Run Code Online (Sandbox Code Playgroud)

快乐的编码!

  • 您可以简单地调用表单的 ValidateChildren,它将触发所有验证事件,如果其中一个被取消,则返回 false。我同意如果您使用 ErrorProvider 则不应使用默认行为“PreventFocusChange”(但那是另一回事,因为 validateChildren 无论如何都会检查它们) (3认同)

RS *_*ley 9

在我自己的应用程序中,我需要在输入时验证尺寸.我使用的顺序如下

  1. 用户选择或输入然后离开控件.
  2. 控件失去焦点并通知View发送它的ID和输入文本.
  3. View检查Shape程序(实现接口的类)创建Form并向其传递ID和条目文本
  4. 形状程序返回响应.
  5. 如果Response为OK,则View会更新Shape类的正确输入.
  6. 如果响应是OK,则View通过接口告诉Form可以将焦点转移到下一个条目.
  7. 如果响应不正常,View将查看响应,并使用Form Interface告知表单要执行的操作.这通常意味着焦点转移回有问题的条目,并显示一条消息,告诉用户发生了什么.

这种方法的优点是验证集中在给定形状程序的一个位置.我不必去修改每个控件,甚至不用担心窗体上不同类型的控件.当我设计软件时,我决定了UI如何用于文本框,列表框,组合框等.另外,不同级别的严重性处理方式也不同.

View负责指导表单通过接口做什么.它实际如何实现是由Form本身在它的Interface实现中处理的.视图不关心表单是否显示黄色表示警告,红色表示错误.只有它处理这两个级别.之后如果出现更好的显示警告与错误的想法,我可以在表单中进行更改,而不是使用View逻辑或Shape程序中的验证.

如果您正在考虑创建一个类来保存验证逻辑,那么您已经在那里了一半,这将使您在新设计中完成其余部分.