[英]WPF Data Binding exception handling
我有一个绑定到 Integer 属性的文本框。 当用户在文本框中输入无法转换为 integer(例如名称)的内容时,将引发异常并且原始属性值不会更改。 我想捕获异常以便我可以禁用连接到该属性的命令? 一般来说,如果可能的话,我该如何从定义属性的视图 model 中做到这一点?
我最近遇到了同样的问题,并且我使用行为来解决它(但如果你不想要,你就不需要它们,它只是为了重用我在不同视图中需要的代码)。 主要思想是在ViewModel中定义一些方法,允许视图通知ViewModel无法检测到的输入中的错误。
因此,首先在ViewModel中定义这些方法。 为简单起见,我只会跟踪错误的数量,但您可以存储更多关于它们的信息(如实际错误):
private int _errorCount = 0;
void AddUIValidationError()
{
_errorCount++;
}
void RemoveUIValidationError()
{
_errorCount--;
}
然后,在View中,注册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}" />
编辑:
另一种方法,除了Riley提到的(这也很好,但要求你将模型中的每个整数属性映射到ViewModel中的新字符串属性)都使用ValidationRules。 您可以添加在解析和调用属性setter之前检查的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>
但无论如何,您需要为要验证的每个非字符串类型创建类,我认为Binding语法现在看起来有点长。
问候
考虑从视图模型而不是从视图中调用命令。
private int _myProperty;
public int MyProperty
{
get
{
return _myProperty;
}
set
{
_myProperty = value;
// See if the value can be parsed to an int.
int potentialInt;
if(int.TryParse(_myProperty, out potentialInt))
{
// If it can, execute your command with any needed parameters.
yourCommand.Execute(_possibleParameter)
}
}
}
这将允许您处理用户键入无法解析为整数的内容,并且只有当用户键入的是整数时才会触发该命令。
(我没有测试这段代码,但我认为它可能会有所帮助。)
我在网上找到的“最佳”解决方案在http://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf中有解释。 /
简而言之,验证错误在View中处理,而不是在ViewModel中处理。 您不需要自己的ValidationRule。 只需在XAML中为按钮添加样式:
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="false" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=TextBox1, Path=(Validation.HasError)}" Value="false" />
<Condition Binding="{Binding ElementName=TextBox2, Path=(Validation.HasError)}" Value="false" />
<Setter Property="IsEnabled" Value="true" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
希望这可以帮助那些偶然发现这个问题的人(我知道这么多年后它不会对OP有所帮助)。
本文为您提供了非常深入的答案,并提供了源代码: http : //karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-结合验证-错误-和-例外/
我们甚至可以直接尝试避免用户在文本框中输入任何字符
<TextBox Name="txtBox" PreviewTextInput="NumberValidationTextBox"/>
在 xaml.cs
private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
{
e.Handled = Regex.IsMatch(e.Text, "[^0-9]+");
}
我们可以检查这个属性的 Model,它在设置它之前检查值以避免任何 null 或空值
private int _number;
public int Number
{
get => _number;
set
{
if(!string.IsNullOrEmpty(value.ToString())
_number = value;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.