我正在尝试让WPF验证在MVVM模式下工作。
在我的视图中,我可以验证像这样的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>
但是,我想通过DelegateCommand处理我的ViewModel中的验证,但是当我使用以下代码尝试它时,我得到显式错误“'{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>
视图模型:
#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
答案 0 :(得分:10)
我不知道这会对你有所帮助,但我会一直提供。
另外,我使用的是Silverlight,而不是WPF。
我没有在我的视图中指定任何验证,也没有在后面的代码和xaml中指定。 My View只对ViewModel上的属性进行数据绑定。
我的所有错误检查/验证都由ViewModel处理。当我遇到错误时,我设置了一个ErrorMessage属性,该属性也绑定到视图。 ErrorMessage文本块(在视图中)有一个值转换器,如果错误为空或为空,则会隐藏它。
通过这种方式进行操作可以轻松地对输入验证进行单元测试。
答案 1 :(得分:6)
以下是使用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;
}
}