C# WPF数据绑定异常处理
我有一个绑定到Integer属性的文本框。当用户在文本框中输入无法转换为整数(例如名称)的内容时,将引发异常,并且原始属性值不会更改。我想捕获异常,以便禁用连接到该属性的命令?一般来说,如果可能的话,如何从定义属性的视图模型中做到这一点?我最近遇到了同样的问题,我使用了行为来解决它(但如果不需要,您不需要它们,它只是为了在不同的视图中重用我需要的一些代码)。主要思想是在ViewModel中定义一些方法,允许视图通知ViewModel无法检测到的输入错误 因此,首先在ViewModel中定义这些方法。为简单起见,我将只跟踪错误的数量,但您可以存储有关错误的更多信息(如实际错误): 然后,在您的视图中,注册C# WPF数据绑定异常处理,c#,.net,wpf,data-binding,C#,.net,Wpf,Data Binding,我有一个绑定到Integer属性的文本框。当用户在文本框中输入无法转换为整数(例如名称)的内容时,将引发异常,并且原始属性值不会更改。我想捕获异常,以便禁用连接到该属性的命令?一般来说,如果可能的话,如何从定义属性的视图模型中做到这一点?我最近遇到了同样的问题,我使用了行为来解决它(但如果不需要,您不需要它们,它只是为了在不同的视图中重用我需要的一些代码)。主要思想是在ViewModel中定义一些方法,允许视图通知ViewModel无法检测到的输入错误 因此,首先在ViewModel中定义这些方
System.Windows.Controls.Validation.ErrorEvent
,这是一个路由事件,可让您知道组件(以前配置为通知数据错误)何时检测到错误(如异常验证错误):
在命令的CanExecute方法中,您将检查ViewModel的_errorCount字段是否大于0,在这种情况下,应禁用该命令
请注意,您必须将ValidatesOnExceptions=True,NotifyOnValidationError=True
添加到绑定中,这样才能正常工作。例:
<TextBox Text="{Binding Path=MyProperty, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
然后,在视图中定义定义IntegerValidationRule的命名空间:
<UserControl
...
xmlns:rules="clr-namespace:MyApplication.ValidationRules"
...>
并在绑定中使用规则:
<TextBox>
<TextBox.Text>
<Binding Path="MyProperty">
<Binding.ValidationRules>
<rules:IntegerValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
但无论如何,您需要为每个要验证的非字符串类型创建类,我认为绑定语法现在看起来有点长
问候语请考虑从视图模型而不是从视图调用命令
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)
}
}
}
这将允许您处理用户键入的无法解析为整数的内容,
并且,只有当用户键入的是整数时,才会触发该命令
(我没有测试这段代码,但我认为它可能会有帮助。)我在网上找到的“最佳”解决方案在
简而言之,验证错误在视图中处理,而不是在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没有帮助)。谢谢,我喜欢你找到了解决问题的方法,但我现在不会接受这个答案,因为我想看看是否有更简单的解决方案。没问题,我也感兴趣。不管怎样,事情并没有那么复杂:)。很高兴你喜欢它,我认为转换解决方案是最正确的,所以我接受了答案。尽管如此,我还是会在将来进一步探讨这个问题,看看是否能找到一个更健壮的解决方案,它不需要仅仅为了实现一个简单的方法而添加另一个类代码>在
if
中,而不是在命令对象中。不要认为OP希望在每个集合中执行该方法。相反,您应该以某种方式禁用该命令。无论如何,这是一个好主意:)我的答案的文字是误导性的。我对它进行了编辑,以更好地反映我的意图。我建议只在需要时从视图模型调用命令,而不是使用绑定。很容易忘记绑定到命令与调用command.Execute()@Riley是一样的,谢谢。我以前没有仔细看过你的答案。但我想告诉你们,我在一篇文章(我不记得了)中读到,你们永远不应该在属性设置器中抛出异常。这可能会造成很多麻烦,尤其是如果该属性是数据绑定的。我接受了您的答案,因为使用字符串是最快的,也是最容易实现的,尽管不是最漂亮的。您是对的,在属性设置器中抛出异常是个坏主意。最好不要生成异常,除非触发异常的条件确实异常。确保使用int.TryParse()而不是int.Parse()。如果传入的内容不是整数,int.TryParse()方法将不会引发异常,因此如果用户键入的内容无法解析为整数,则不必引发任何异常。
<TextBox>
<TextBox.Text>
<Binding Path="MyProperty">
<Binding.ValidationRules>
<rules:IntegerValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
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)
}
}
}
<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>