【问题标题】:How can I get WPF to NOT display validation errors upon initial display of control?如何让 WPF 在初始显示控件时不显示验证错误?
【发布时间】:2012-08-16 09:27:52
【问题描述】:

当我第一次向用户显示我的屏幕时,我宁愿在用户有机会填写任何表单字段之前不显示所有必填字段的验证消息等。我已将绑定上的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);
    }
}

【问题讨论】:

  • 你为这个布赖恩找到了最好的方法吗? :\

标签: wpf validation


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    如果您努力发布相关代码/XAML 的 sn-p,您可以获得更好的答案。这将使重现和消除大部分猜测变得更容易。

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

    【讨论】:

    • 我实际上没有使用 ValidationRules,我正在实现 IDataErrorInfo。应该在问题中包含更多细节,抱歉。
    【解决方案3】:

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

    我在视图绑定属性的每个设置器中调用了一个名为 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 indexer 属性中,我执行以下操作(我将其拆分,因此也可以手动调用 '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(() =&gt; CanConfirm); 中发表评论,并将其绑定到您的确认按钮IsEnabled={Binding CanConfirm} 和相关属性:

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

    只有当您的表单也有效时,您的按钮才会启用。 :)

    享受吧!祝 WPF 这个庞然大物好运。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      相关资源
      最近更新 更多