WPF 数据绑定异常处理

Ibr*_*jar 5 .net c# data-binding wpf

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

Dan*_*tro 5

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

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

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

void RemoveUIValidationError()
{
   _errorCount--;
}
Run Code Online (Sandbox Code Playgroud)

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

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

请注意,您应该添加ValidatesOnExceptions=True, NotifyOnValidationError=True到您的绑定中才能正常工作。前任:

<TextBox Text="{Binding Path=MyProperty, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
Run Code Online (Sandbox Code Playgroud)

编辑:

除了 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<UserControl 
...
    xmlns:rules="clr-namespace:MyApplication.ValidationRules"
...>
Run Code Online (Sandbox Code Playgroud)

并在绑定中使用该规则:

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

              <rules:IntegerValidationRule/>
           </Binding.ValidationRules>
       </Binding>
    </TextBox.Text>
</TextBox>
Run Code Online (Sandbox Code Playgroud)

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

问候


ril*_*ell 0

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

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将允许您处理用户键入无法解析为整数的内容,并且仅当用户键入的内容是整数时才会触发命令。

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