How can I handle a Validation.Error in my ViewModel instead of my View's code behind?

后端 未结 2 1945
囚心锁ツ
囚心锁ツ 2020-12-06 07:30

I\'m trying to get WPF validation to work within the MVVM pattern.

In my View, I can validate a TextBox like this which gets handled by the code-behind method \"Hand

相关标签:
2条回答
  • 2020-12-06 07:50

    I don't know if this will help you, but I'll offer it all the same.

    Also, I'm using Silverlight, not WPF.

    I don't specify any validation in my Views, neither in the code behind nor the xaml. My View has only data bindings to properties on the ViewModel.

    All my error checking/validation is handled by the ViewModel. When I encounter an error, I set a ErrorMessage property, which is bound to the view as well. The ErrorMessage textblock (in the view) has a value converter which hides it if the error is null or empty.

    Doing things this way makes it easy to unit test input validation.

    0 讨论(0)
  • 2020-12-06 07:58

    Here's a way to do this using Expression Blend 3 behaviors. I wrote a ValidationErrorEventTrigger because the built-in EventTrigger doesn't work with attached events.

    View:

    <TextBox>
    <i:Interaction.Triggers>
        <MVVMBehaviors:ValidationErrorEventTrigger>
            <MVVMBehaviors:ExecuteCommandAction TargetCommand="HandleErrorCommand" />
        </MVVMBehaviors:ValidationErrorEventTrigger>
    </i:Interaction.Triggers>
    <TextBox.Text>
        <Binding Path="FirstName"
                 Mode="TwoWay"
                 NotifyOnValidationError="True">
            <Binding.ValidationRules>
                <ExceptionValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
    

    ViewModel: (could be unchanged, but here's a look at how I dug into the validation arguments to find the error message when using the exception validation rule)

        public ICommand HandleErrorCommand
        {
            get
            {
                if (_handleErrorCommand == null)
                    _handleErrorCommand = new RelayCommand<object>(param => OnDisplayError(param));
                return _handleErrorCommand;
            }
        }
    
        private void OnDisplayError(object param)
        {
            string message = "Error!";
            var errorArgs = param as ValidationErrorEventArgs;
            if (errorArgs != null)
            {
                var exception = errorArgs.Error.Exception;
                while (exception != null)
                {
                    message = exception.Message;
                    exception = exception.InnerException;
                }
            }
            Status = message;
        }
    

    ValidationErrorEventTrigger:

    public class ValidationErrorEventTrigger : EventTriggerBase<DependencyObject>
    {
        protected override void OnAttached()
        {
            Behavior behavior = base.AssociatedObject as Behavior;
            FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;
    
            if (behavior != null)
            {
                associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
            }
            if (associatedElement == null)
            {
                throw new ArgumentException("Validation Error Event trigger can only be associated to framework elements");
            }
            associatedElement.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.OnValidationError));
        }
        void OnValidationError(object sender, RoutedEventArgs args)
        {
            base.OnEvent(args);
        }
        protected override string GetEventName()
        {
            return Validation.ErrorEvent.Name;
        }
    }
    
    0 讨论(0)
提交回复
热议问题