Как я могу обработать Validation.Error в моей ViewModel вместо кода моего View? - PullRequest
7 голосов
/ 28 мая 2009

Я пытаюсь настроить проверку WPF для работы с шаблоном MVVM.

В моем View я могу проверить TextBox, как этот, который обрабатывается методом code-behind "HandleError", который отлично работает:

<TextBox Width="200"
         Validation.Error="HandleError">
    <TextBox.Text>
        <Binding Path="FirstName"
             NotifyOnValidationError="True"
             Mode="TwoWay">
            <Binding.ValidationRules>
                <validators:DataTypeLineIsValid/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Однако я хотел бы обработать проверку в моей ViewModel через DelegateCommand, но когда я пробую его с помощью следующего кода, я получаю явную ошибку " '{Binding HandleErrorCommand}' не является допустимым методом обработчика событий name. Допустимы только методы экземпляра в сгенерированном классе или классе с выделенным кодом."

Есть ли обходной путь для этого, чтобы мы могли обрабатывать проверки в шаблоне MVVM?

Вид:

<TextBox Width="200"
         Validation.Error="{Binding HandleErrorCommand}">
    <TextBox.Text>
        <Binding Path="FirstName"
             NotifyOnValidationError="True"
             Mode="TwoWay">
            <Binding.ValidationRules>
                <validators:DataTypeLineIsValid/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

ViewModel:

#region DelegateCommand: HandleError
private DelegateCommand handleErrorCommand;

public ICommand HandleErrorCommand
{
    get
    {
        if (handleErrorCommand == null)
        {
            handleErrorCommand = new DelegateCommand(HandleError, CanHandleError);
        }
        return handleErrorCommand;
    }
}

private void HandleError()
{
    MessageBox.Show("in view model");
}

private bool CanHandleError()
{
    return true;
}
#endregion

Ответы [ 2 ]

10 голосов
/ 28 мая 2009

Не знаю, поможет ли это вам, но я все равно предложу.

Также я использую Silverlight, а не WPF.

Я не указываю никакой проверки в моих представлениях, ни в коде, ни в xaml. My View имеет только привязки данных к свойствам в ViewModel.

Вся моя проверка / проверка ошибок обрабатывается ViewModel. Когда я сталкиваюсь с ошибкой, я устанавливаю свойство ErrorMessage, которое также привязано к представлению. У текстового блока ErrorMessage (в представлении) есть конвертер значений, который скрывает его, если ошибка нулевая или пустая.

Подобные действия облегчают проверку входных данных модульного теста.

6 голосов
/ 29 мая 2009

Вот способ сделать это, используя Expression Blend 3 поведения. Я написал ValidationErrorEventTrigger, потому что встроенный EventTrigger не работает с прикрепленными событиями.

Вид:

<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: (может быть неизменным, но вот посмотрите, как я копался в аргументах проверки, чтобы найти сообщение об ошибке при использовании правила проверки исключений)

    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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...