C# 如何处理 ViewModel 中的 Validation.Error 而不是背后的 View 代码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/921601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I handle a Validation.Error in my ViewModel instead of my View's code behind?
提问by Edward Tanguay
I'm trying to get WPF validation to work within the MVVM pattern.
我试图让 WPF 验证在 MVVM 模式中工作。
In my View, I can validate a TextBox like this which gets handled by the code-behind method "HandleError", which works fine:
在我的视图中,我可以验证这样的 TextBox,它由代码隐藏方法“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>
However, I would like to handle the validation in my ViewModel via a DelegateCommand but when I try it with the following code, I get the explicit error "'{Binding HandleErrorCommand}' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid."
但是,我想通过 DelegateCommand 处理我的 ViewModel 中的验证,但是当我使用以下代码尝试它时,我收到显式错误“ '{Binding HandleErrorCommand}'不是有效的事件处理程序方法名称。只有实例方法生成的或代码隐藏的类是有效的。”
Are there any workaround for this so that we can handle validations within a MVVM pattern?
是否有任何解决方法,以便我们可以在 MVVM 模式中处理验证?
View:
看法:
<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
采纳答案by Matt Brunell
I don't know if this will help you, but I'll offer it all the same.
我不知道这是否对你有帮助,但我会提供同样的。
Also, I'm using Silverlight, not WPF.
另外,我使用的是 Silverlight,而不是 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.
我没有在我的视图中指定任何验证,无论是在后面的代码中还是在 xaml 中。我的视图只有数据绑定到 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.
我所有的错误检查/验证都由 ViewModel 处理。当我遇到错误时,我设置了一个 ErrorMessage 属性,该属性也绑定到视图。ErrorMessage 文本块(在视图中)有一个值转换器,如果错误为空或为空,它将隐藏它。
Doing things this way makes it easy to unit test input validation.
以这种方式做事可以很容易地对输入验证进行单元测试。
回答by Ben Reierson
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.
这是一种使用 Expression Blend 3 行为执行此操作的方法。我写了一个 ValidationErrorEventTrigger 因为内置的 EventTrigger 不适用于附加的事件。
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)
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;
}
}