C# 使用INotifyDataErrorInfo处理转换异常

C# 使用INotifyDataErrorInfo处理转换异常,c#,.net,wpf,validation,data-binding,C#,.net,Wpf,Validation,Data Binding,我的视图中有一个文本框,用户可以在其中键入TCP端口值。 文本框直接绑定到模型的端口属性(Int32类型),因为ViewModel提供了完整的绑定模型。该模型继承自ObserveObject,因此直接绑定到该模型效果良好 我在模型中使用INotifyDataErrorInfo,端口属性验证属性setter中的值(它必须大于0) 我在视图中有一个按钮,它绑定到模型的HasError()方法,并根据HasError()的布尔返回值设置其IsEnabled状态 现在来看问题,如果用户输入“Hello

我的视图中有一个文本框,用户可以在其中键入TCP端口值。 文本框直接绑定到模型的端口属性(Int32类型),因为ViewModel提供了完整的绑定模型。该模型继承自ObserveObject,因此直接绑定到该模型效果良好

我在模型中使用INotifyDataErrorInfo,端口属性验证属性setter中的值(它必须大于0)

我在视图中有一个按钮,它绑定到模型的HasError()方法,并根据HasError()的布尔返回值设置其IsEnabled状态

现在来看问题,如果用户输入“Hello world”,WPF绑定引擎将引发异常。在这种情况下,永远不会执行属性设置器,因此对于这种无效输入,HasError()永远不会更改为true

在这种情况下,我当然可以为视图中的文本框设置“ValidatesOnExceptions=True”,至少让文本框显示其验证错误模板,但按钮仍然不会被禁用

问题,建议的解决方案是什么?如何处理自动转换失败导致ViewModel/模型验证无法执行的情况

如果验证是在文本框字符串上执行的,而不是在Int32类型上执行的,那么我可以接受这样一种解决方案,在WPF绑定引擎执行到Int32的失败的自动类型转换之前执行

我真正想要避免的一个解决方案是让我的ViewModel/Model属性始终为string类型,在setter中验证字符串,然后尝试手动将其转换为正确的类型(在本例中为Int32)。必须有更好的解决方案来避免所有此类手动强制转换


使用ValidationRules时,可以告诉验证引擎在自动转换之前执行ValidationRule。我真正想要的是在自动转换完成之前执行INotifyDataErrorInfo验证的一种方法。

您所经历的困难就是为什么不应该从视图直接绑定到模型的示例。视图模型的整体观点是在视图和与底层模型交互的代理之间来回转换表示关注点


例如:如果视图为端口提供字符串,则视图模型将验证该字符串并将其(如果有效)转换为模型的整数,或者通过任何错误通知机制通知视图无效输入。

属性不能设置为
int
值以外的任何值。当您尝试将其设置为“Hello world”时,绑定引擎将捕获异常并为您处理它

如果要自己执行验证或自定义错误消息,可以定义自定义的
ValidationRule
,并将其
ValidationStep
属性设置为
RawProposedValue
,以便在值转换发生之前应用它:

public class StringToIntValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        int i;
        if (int.TryParse(value.ToString(), out i))
            return new ValidationResult(true, null);

        return new ValidationResult(false, "Please enter a valid integer value.");
    }
}
XAML:

<TextBox>
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:StringToIntValidationRule ValidationStep="RawProposedValue"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>


请注意,这种验证或自定义不涉及视图模型。这是一个框架/视图/控制的东西。

对于什么问题,推荐的解决方案是什么?显然,视图模型无法处理此类异常,因为它从未涉及。当您尝试将字符串转换为int时发生的异常已由框架为您处理,那么您的实际问题是什么?是的,在自动转换之前,我如何执行验证。我更新了问题以使其更清楚。在视图中使用ValidationRule。请参考我的答案。好的,如果没有所有这些类型之间的手动翻译,就没有办法解决这个问题。当模型已经支持绑定(ObservableObject)时,似乎有很多不必要的代码。如果您是这样想的,那么不应该将视图模型属性的类型从
int
更改为
string
。视图模型不负责处理视图设置其属性的方式。@mm8请解释,如果我不将VM属性类型更改为字符串,在VM属性中执行的验证将永远不会执行。我现在在VM中使用字符串,然后在模型中设置值之前将其转换为Int。但它也有一个缺点。如果模型更改Int值,则绑定将不会更新,除非我在VM中显式订阅模型的事件。这不是一个干净的解决方法,但似乎不是更好的方法。@Johan:您可以使用附加的行为绑定Validation.HasError属性:是的,我知道ValidationRule。问题是,正如您所说的,虚拟机不涉及,如果视图中存在任何验证错误,并且基于其他对象的某些状态,我希望禁用其他元素(例如按钮)。我看不出使用ValidationRule解决这个问题的好方法。目前button命令绑定到RelayCommand。relaycommand根据INotifyDataErrorInfo的HasError和其他对象的状态设置按钮的启用状态。