如何在初始显示控件时让WPF不显示验证错误?

时间:2010-05-12 19:14:06

标签: wpf validation

当我第一次向用户显示我的屏幕时,在用户有机会填写任何表单字段之前,我宁愿没有显示所有必需字段的验证消息。我已将绑定UpdateSourceTrigger设置为LostFocus,但错误仍会在第一次显示控件时显示。有没有办法解决这个问题?

XAML:

<TextBox Text="{Binding Path=OpeningOdometer, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}" />

视图模型:

[Required(ErrorMessage = "Please enter the opening odometer.")]
[Range(0, Double.MaxValue, ErrorMessage = "Opening Odometer must be a positive number")]        
public string OpeningOdometer
{
    get { return _openingOdometer; }
    set
    {
        _openingOdometer = value;
        NotifyOfPropertyChange(() => OpeningOdometer);
    }
}

// Implementation of IDataErrorInfo
public string this[string columnName]
{
    get
    {
        // This uses the System.ComponentModel.DataAnnotations placed on
        // the OpeningOdometer property to produce an error string
        // if the value of the property is in violation of any of the 
        // annotated rules.
        return _valHelper.GetErrorsForProperty(columnName, this);
    }
}

3 个答案:

答案 0 :(得分:8)

我没有将验证逻辑放在索引器中。这将控制验证的时间到视图。在您的方案中,视图会在询问属性的错误信息时触发验证。我不知道会发生什么情况,我打赌你也不会。

相反,我在其setter中放置了属性的验证逻辑(更准确地说,是对验证函数的调用)。我将错误消息存储在键入属性名称的字典中,并让索引器查找该属性的错误消息。

默认情况下,错误消息是最新的属性的当前值。每当视图更新属性并请求其新的错误信息时,它都会得到正确的答案。

但是你也可以对字典中的实际内容进行相当精细的控制。如果您希望UI中的属性显示为有效,只需在字典中清除其错误消息(并引发PropertyChanged,以便UI知道获取新的错误消息)。或者,您可以在构造视图模型对象时设置属性的支持字段而不是属性本身,从而绕过验证。

答案 1 :(得分:2)

如果您努力发布相关代码/ XAML的片段,则可以获得更好的答案。这样可以更容易地重现并消除大部分的猜测。

尝试在验证规则上设置ValidatesOnTargetUpdated="False",看看是否有帮助。

答案 2 :(得分:2)

只是为了说明我是如何使用IDataErrorInfo ...

来处理此问题的

我在视图绑定属性的每个setter中调用了一个名为OnDataUpdated()的新方法,例如:

    private string username;
    public string Username
    {
        get { return username; }
        set
        {
            username = value;
            OnDataUpdated();
        }
    }

    private string password;
    public string Password
    {
        get { return password; }
        set
        {
            password = value;
            OnDataUpdated();
        }
    }

然后在OnDataUpdated()内标记私有字段布尔值为true,表示数据第一次发生了变化(FormType只是我的业务案例所必需的):

private void OnDataUpdated()
{
   dataChanged = true;
   // .. Any other universal RaisePropertyChanged() events you may want to call to get your UI into sync. Eg. RaisePropertyChanged(() => CanConfirm);
}

然后在我的IDataErrorInfo索引器属性中,我执行以下操作(我将其拆分,因此可以手动调用'ValidForm()'以执行表单验证。

public string this[string columnName]
        {
            get
            {
                string result = null;
                if (columnName == "Username")
                {
                    // If other payment amounts have fully paid for balance, and cash amount has been entered, deny
                    if (!ValidForm(FormType.Step1, columnName))
                        result = "Please enter the username field.";
                }
                else if (columnName == "Password")
                {
                    if (!ValidForm(FormType.Step1, columnName))
                        result = "Please enter the password field.";
                }
                return result;
            }
        }

        /// <summary>
        /// Test if valid form.
        /// </summary>
        /// <param name="formType">Specify which form we should validate.</param>
        /// <param name="columnName">If ommitted, entire form will be validated.</param>
        /// <returns></returns>
        private bool ValidForm(FormType formType, string columnName = null)
        {
            // This field is used to denote when data has changed on the form.
            // If data has changed, we know we can activate any form validation.
            // We do not activate the form validation until after a user has typed
            // something in at least.
            if (!dataChanged) return true;

            var errors = false;
            if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Username") && string.IsNullOrEmpty(Username)))
                errors = true;
            if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Password") && string.IsNullOrEmpty(Password)))
                errors = true;
            return !errors;
        }

工作得很漂亮。现在,我只在用户编辑表单后出现验证样式。

如果你想要一些额外的锦上添花,你可以在RaisePropertyChanged(() => CanConfirm);方法的OnDataUpdated()中发表评论并将其与相关属性的确认按钮IsEnabled={Binding CanConfirm}绑定:

/// <summary>
/// Can the user confirm step 1?
/// </summary>
public bool CanConfirm
{
    get { return ValidForm(FormType.Step1); }
}

并且只有在您的表单有效时才会启用您的按钮。 :)

享受!祝WPF的庞然大物好运。