Loading

WPF ValidationRules(MVVM 数据验证)

对于WPF中的验证, View验证实现起来很简单, 可以通道 Validation.ErrorEvent 冒泡传递到View的逻辑树上, 只是, 通常这样做的情况下, 我们需要为View添加事件代码监听这类错误事件, 然后进行处理。
这样做可以说是非常简单, 但是这样的硬编码的, 基本上每个模块每个功能, 你都必不可少的为其进行重复的工作, 这是一项非常枯燥且无聊的体力活!
于是, 则考虑MVVM的架构中, 如何把这种模式传递到ViewModel中, 使得前端的验证, 对于ViewModel仍然有效。
实现的原理, 如图所示:

在此之前, 对于View前端验证需要做的一些操作步骤,

  • 1.为验证的属性添加自定义验证类
  • 2.设置验证错误的通知属性 NotifyOnValidationError="True" 。 注: 如此一来, 则可以产生Validation.ErrorEvent事件
  • 3.通过自定义的 ValidationExceptionBehavior 继承于 Behavior, 用于监听 Validation.ErrorEvent 的错误事件。
  • 4.在 ValidationExceptionBehavior 中通过 AssociatedObjectde的DataContex获取到关联当前View的DataContex, 从而改变DataContext的后端验证条件。

1.设置属性自定义的验证类并添加 NotifyOnValidationError="True" 属性

                        <TextBox  Margin="15 0 10 0" 
                                 Style="{StaticResource MaterialDesignFloatingHintTextBox}"  materialDesign:HintAssist.Hint="登录名 *">
                            <TextBox.Text>
                                <Binding Path="Model.Account" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True">
                                    <Binding.ValidationRules>
                                        <domain:CustomizeValidationRule validationType="Str" 
                                                                        minLength="3" maxLength="10"
                                                                        errorMessage="输入长度范围 [3-10]字" 
                                                                        ValidatesOnTargetUpdated="True" />
                                    </Binding.ValidationRules>
                                </Binding>
                            </TextBox.Text>
                        </TextBox>

2.自定义 IValidationExceptionHandler 接口, ViewModel继承IValidationExceptionHandler , 用于接收前端的验证结果。

public interface IValidationExceptionHandler
    {
        /// <summary>
        /// 是否有效
        /// </summary>
        bool IsValid
        {
            get;
            set;
        }
    }

3. 自定义 ValidationExceptionBehavior, 用于监听处理View的错误事件

    /// <summary>
    /// 验证行为类,可以获得附加到的对象
    /// </summary>
    public class ValidationExceptionBehavior : Behavior<FrameworkElement>
    {
        /// <summary>
        /// 错误计数器
        /// </summary>
        private int _validationExceptionCount = 0;
        
        /// <summary>
        /// 附加对象时
        /// </summary>
        protected override void OnAttached()
        {
            //附加对象时,给对象增加一个监听验证错误事件的能力,注意该事件是冒泡的
            this.AssociatedObject.AddHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(this.OnValidationError));
        }
        
        #region 获取实现接口的对象

        /// <summary>
        /// 获取对象
        /// </summary>
        /// <returns></returns>
        private IValidationExceptionHandler GetValidationExceptionHandler()
        {
            if (this.AssociatedObject.DataContext is IValidationExceptionHandler)
            {
                var handler = this.AssociatedObject.DataContext as IValidationExceptionHandler;

                return handler;
            }

            return null;
        }

        #endregion
        
        #region 验证事件方法

        /// <summary>
        /// 验证事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnValidationError(object sender, ValidationErrorEventArgs e)
        {
            try
            {
                var handler = GetValidationExceptionHandler();

                var element = e.OriginalSource as UIElement;

                if (handler == null || element == null)
                    return;

                if (e.Action == ValidationErrorEventAction.Added)
                {
                    _validationExceptionCount++;
                    
                }
                else if (e.Action == ValidationErrorEventAction.Removed)
                {
                    _validationExceptionCount--;
                }
                handler.IsValid = _validationExceptionCount == 0;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion
    }

4. View容器最外层注册添加的监听错误事件 ValidationExceptionBehavior

   <i:Interaction.Behaviors>
        <domain:ValidationExceptionBehavior></domain:ValidationExceptionBehavior>
    </i:Interaction.Behaviors>

5. ViewModel 通过实现 IValidationExceptionHandler 来获取前端的验证结果

根据前端验证的结果, 正确保存, 错误进行提示

        public override void Save()
        {
            if (!this.IsValid)
            {
                MessageBox.Show("输入的格式有误,请重新输入!");
                return;
            }
            base.Save();
        }

效果:

posted @ 2019-08-30 00:44  痕迹g  阅读(10049)  评论(0编辑  收藏  举报