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

13
当我第一次向用户展示屏幕时,我希望在用户填写表单字段之前不要显示所有必填字段和其他验证消息。 我已将绑定的 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);
    }
}

1
你有想出最好的方法吗,Brian?:\ - GONeale
3个回答

8
我不会在索引器中放置验证逻辑。这将控制验证的时间交给了视图。在您的方案中,视图在请求属性的错误信息时触发验证。我不知道那会发生在什么情况下,我打赌你也不知道。
相反,我将属性的验证逻辑(更准确地说是对验证函数的调用)放在它的setter中。我将错误消息存储在以属性名称为键的字典中,并让索引器查找该属性的错误消息。
因此,默认情况下,错误消息与属性的当前值保持最新。每当视图更新属性并请求其新的错误信息时,它将得到正确的答案。
但是,您还可以对字典中实际包含的内容进行精细控制。如果您希望属性在UI中显示为有效,请清除字典中的错误消息(并引发PropertyChanged事件,以便UI知道获取新的错误消息)。或者,您可以在构造视图模型对象时设置属性的支持字段而不是属性本身,从而绕过验证。

3

如果您能够尽力发布相关代码/XAML的片段,您将获得更好的答案。这将使复制和消除大部分猜测变得更加容易。

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


2
我实际上没有使用ValidationRules,而是实现了IDataErrorInfo。在问题中应该包含更多细节,抱歉。 - Brian Sullivan

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;
        }

非常好用。现在,仅当用户编辑表单后,才会出现验证样式。

如果您想要更完美的效果,您可以在OnDataUpdated()方法中的RaisePropertyChanged(() => CanConfirm);中添加注释,并将其绑定到确认按钮IsEnabled={Binding CanConfirm}与相应的属性:

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

只有在表单验证通过时,您的按钮才会启用。:)

祝你好运,享受吧!面对庞大的WPF,请加油。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接