WPF 数据绑定异常处理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13335787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:09:11  来源:igfitidea点击:

WPF Data Binding exception handling

c#.netwpfdata-binding

提问by Ibrahim Najjar

I have a textbox that is bound to an Integer property. when the user enters something in the textbox that can't be converted to an integer (eg. name) an exception will be thrown and the original property value won't change. i want to catch the exception so that i can disable a command that is connected to that property ? how can i do that in general and if possible from the view model where the property is defined ?

我有一个绑定到 Integer 属性的文本框。当用户在文本框中输入无法转换为整数(例如名称)的内容时,将引发异常并且原始属性值不会更改。我想捕获异常以便我可以禁用连接到该属性的命令?如果可能的话,我该如何从定义属性的视图模型中做到这一点?

采纳答案by rileymcdowell

Consider calling the command from the view model instead of from the view.

考虑从视图模型而不是从视图调用命令。

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)
        }
    }
}

This will allow you to handle the user typing things that cannot be parsed to an integer, and you will only fire the command when what the user typed is an integer.

这将允许您处理用户输入无法解析为整数的内容,并且您只会在用户输入的是整数时触发该命令。

(I didn't test this code, but I think it might be helpful.)

(我没有测试这段代码,但我认为它可能会有所帮助。)

回答by Daniel Castro

I faced the same issue recently and I used behaviors to solve it (but you don't need them if you don't want, it was just for reusing some code I needed among different views). The main idea is to define some methods in the ViewModel that allow the view to notify errors in the input that the ViewModel cannot detect.

我最近遇到了同样的问题,我使用行为来解决它(但如果你不想,你不需要它们,它只是为了在不同的视图中重用我需要的一些代码)。主要思想是在 ViewModel 中定义一些方法,允许视图通知输入中 ViewModel 无法检测到的错误。

So, first define those methods in your ViewModel. For simplicity, I will only keep track of the number of errors, but you can store more info about them (like the actual error):

因此,首先在您的 ViewModel 中定义这些方法。为简单起见,我只会跟踪错误的数量,但您可以存储有关它们的更多信息(例如实际错误):

private int _errorCount = 0;
void AddUIValidationError()
{
   _errorCount++;
}

void RemoveUIValidationError()
{
   _errorCount--;
}

Then, in your View, you register for System.Windows.Controls.Validation.ErrorEvent, which is a routed event that lets you know when a component (previously configured to notify data errors) detects errors (like an exception validation error):

然后,在您的视图中,注册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();
            }
        }
    }
}

In the CanExecute method of your Command, you would check if the _errorCount field of your ViewModel is more than 0, and in that case, the command should be disabled.

在命令的 CanExecute 方法中,您将检查 ViewModel 的 _errorCount 字段是否大于 0,在这种情况下,应禁用该命令。

Please note that you should must add ValidatesOnExceptions=True, NotifyOnValidationError=Trueto your bindings so this can work. Ex:

请注意,您必须添加ValidatesOnExceptions=True, NotifyOnValidationError=True到您的绑定中,这样才能工作。前任:

<TextBox Text="{Binding Path=MyProperty, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />

EDIT:

编辑:

Another approach, apart from what Riley mentioned (which is also good, but requires that you map each integer property from your model to a new string property in your ViewModel) is using ValidationRules. You can add ValidationRules that are checked before parsing and calling the property setter. So you could, for example, inherit from ValidationRule and implement the Validate method to ensure that the string can be parsed to an integer. Example:

除了 Riley 提到的方法(这也很好,但要求您将模型中的每个整数属性映射到 ViewModel 中的新字符串属性)之外,另一种方法是使用 ValidationRules。您可以添加ValidationRule在解析和调用属性设置器之前检查的 s。因此,例如,您可以继承 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);
    }
}

And then, in your view define the namespace where IntegerValidationRule is defined:

然后,在您的视图中定义定义 IntegerValidationRule 的命名空间:

<UserControl 
...
    xmlns:rules="clr-namespace:MyApplication.ValidationRules"
...>

And use the rule in your bindings:

并在您的绑定中使用规则:

<TextBox>
    <TextBox.Text>
       <Binding Path="MyProperty">
           <Binding.ValidationRules>

              <rules:IntegerValidationRule/>
           </Binding.ValidationRules>
       </Binding>
    </TextBox.Text>
</TextBox>

But anyway, you'll need to create classes for each non-string type you want to validate, and I think the Binding syntax now looks a bit long.

但无论如何,您需要为要验证的每个非字符串类型创建类,而且我认为 Binding 语法现在看起来有点长。

Greetings

你好

回答by Bernhard Hiller

The "best" solution I've found in the web is explained at http://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf/

我在网上找到的“最佳”解决方案在http://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf 中有解释/

In short, the Validation errors are dealt with in the View, not in the ViewModel. You do not need your own ValidationRule. Just add a style to your button in XAML:

简而言之,验证错误是在 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>

Hope this helps someone who stumbles upon this question (I am aware that it won't likely help the OP so many years later).

希望这能帮助那些偶然发现这个问题的人(我知道这么多年后它不太可能对 OP 有帮助)。

回答by Bill Tarbell

This article here has a very in depth answer for you with source code provided as well: http://karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-binding-validation-errors-and-exceptions/

这篇文章在这里为您提供了非常深入的答案,并提供了源代码:http: //karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-绑定验证错误和异常/