我最近遇到了同样的问题,我使用行为来解决它(但如果你不想,你不需要它们,这只是为了在不同视图中重用我需要的一些代码)。主要思想是在 ViewModel 中定义一些方法,允许视图通知 ViewModel 无法检测到的输入错误。
因此,首先在 ViewModel 中定义这些方法。为简单起见,我将仅跟踪错误数量,但您可以存储有关它们的更多信息(例如实际错误):
private int _errorCount = 0;
void AddUIValidationError()
{
_errorCount++;
}
void RemoveUIValidationError()
{
_errorCount--;
}
然后,在您的视图中,您注册System.Windows.Controls.Validation.ErrorEvent
,这是一个路由事件,让您知道组件(之前配置为通知数据错误)何时检测到错误(例如异常验证错误):
public partial class MyView : UserControl // or whatever it is
{
public MyView(MyViewModel viewModel)
{
// Possibly ensure that viewModel is not null
InitializeComponent();
_myViewModel = viewModel;
this.AddHandler(System.Windows.Controls.Validation.ErrorEvent, new RoutedEventHandler(OnValidationRaised));
}
private MyViewModel _myViewModel;
private void OnValidationRaised(object sender, RoutedEventArgs e)
{
var args = (System.Windows.Controls.ValidationErrorEventArgs)e;
if (_myViewModel != null)
{
// Check if the error was caused by an exception
if (args.Error.RuleInError is ExceptionValidationRule)
{
// Add or remove the error from the ViewModel
if (args.Action == ValidationErrorEventAction.Added)
_myViewModel.AddUIValidationError();
else if (args.Action == ValidationErrorEventAction.Removed)
_myViewModel.RemoveUIValidationError();
}
}
}
}
在 Command 的 CanExecute 方法中,您将检查 ViewModel 的 _errorCount 字段是否大于 0,在这种情况下,应禁用该命令。
请注意,您必须添加ValidatesOnExceptions=True, NotifyOnValidationError=True
到你的绑定,这样就可以工作了。前任:
<TextBox Text="{Binding Path=MyProperty, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
EDIT:
除了 Riley 提到的方法(这也很好,但需要将模型中的每个整数属性映射到 ViewModel 中的新字符串属性)之外,另一种方法是使用 ValidationRules。你可以加ValidationRule
在解析和调用属性设置器之前检查的。例如,您可以继承 ValidationRule 并实现 Validate 方法以确保字符串可以解析为整数。
例子:
public class IntegerValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
int number;
if(Int32.TryParse((string)value, out number) == false)
return new ValidationResult(false, "It is not a valid number");
return new ValidationResult(true, null);
}
}
然后,在您的视图中定义定义 IntegerValidationRule 的命名空间:
<UserControl
...
xmlns:rules="clr-namespace:MyApplication.ValidationRules"
...>
并在绑定中使用该规则:
<TextBox>
<TextBox.Text>
<Binding Path="MyProperty">
<Binding.ValidationRules>
<rules:IntegerValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
但无论如何,您需要为要验证的每个非字符串类型创建类,而且我认为绑定语法现在看起来有点长。
问候