如何捕获PropertyChanged事件期间抛出的异常

时间:2012-10-01 15:16:47

标签: c# wpf mvvm inotifypropertychanged

我正在使用MVC \ MVVM和WPF。我有一个绑定到模型和控制器的表单,它捕获PropertyChanged事件并评估业务规则和验证。 好吧,我想在验证错误时弹出一条消息告诉用户有什么问题以及如何修复它。但我不确定控制器的“正确”方式。我想抛出一个可以被视图捕获的异常,但我无法弄清楚如何。 我已经尝试过Dispatcher.Invoke(),但这只是在应用程序级别给我一个未处理的异常。

如何捕获从Controller中的PropertyChanged事件处理程序生成的异常?

编辑:具体来说,我有一个组合框,里面有折扣列表。我不能允许不恰当的选择,但我必须通知用户选择不合适的原因。这不像在其中包含整数的文本框那么明显。我需要告诉用户客户填写调查的日期。他们不能两次使用该折扣。我不想从列表中排除调查折扣,因为这对用户来说只是一个错误。我需要向他们展示折扣并告诉他们客户已使用该折扣而不能再使用它。

编辑2:我查看了ValidationRule类,因为我必须使用数据库查找,所以我不知道如何保留模型中的所有内容并且仍然在Controller中有业务规则。我看过IDataErrorInfo,但这要求我将我的模型包装在我的Controller中并绑定到Controller,但仅限于一个字段。我认为在这种情况下最好的做法是让Controller在View上调用一个方法并弹出一条消息。

1 个答案:

答案 0 :(得分:2)

你走错了路。

在MVVM中处理验证的一个好方法是在绑定上实现IDataErrorInfo并将ValidatesOnDataErrors设置为true。您几乎肯定也希望启用ValidatesOnExceptions以获得完整性,并NotifyOnValidationError以便绑定引擎触发您绑定属性的控件上的Validation.Error附加事件。

有关详细信息,请参阅WPF中MSDN documentation for data binding的验证部分。

一些提示:

  • .NET 4.5引入了INotifyDataErrorInfo和相应的ValidatesOnNotifyDataErrors绑定属性,与IDataErrorInfo相比,提供了增强的验证功能;你可能想看一下。
  • 您不需要在IDataErrorInfo.Error内实际执行任何有意义的操作,因为它由Windows窗体基础结构使用并在WPF中被忽略。你甚至可以让getter throw NotImplementedException
  • 有很好的阅读材料说明了这种方法,并附有示例和代码herehere

更新:澄清和示例代码

此验证模型不涉及自己实现ValidationRule;您的模型(即绑定源)只需要实现两个接口之一。如何实现界面完全取决于您;在过去的项目中,我使用

实现了基本的异步验证
public interface IDelegatedValidation : IDataErrorInfo
{
    /// <summary>
    /// Occurs when validation is to be performed.
    /// </summary>
    event EventHandler<DelegatedValidationEventArgs> ValidationRequested;
}

public class DelegatedValidationEventArgs : EventArgs
{
    public DelegatedValidationEventArgs(string propertyName)
    {
        this.PropertyName = propertyName;
    }

    public string PropertyName { get; private set; }

    public bool Handled { get; set; }

    public string ValidationError { get; set; }
}

模型通过公开事件和

来实现IDelegatedValidation
string IDataErrorInfo.this[string columnName]
{
    get { return this.GetValidationError(columnName); }
}

private string GetValidationError(string propertyName)
{
    var args = new DelegatedValidationEventArgs(propertyName);
    this.OnValidationRequested(args);
    return args.ValidationError;
}

protected virtual void OnValidationRequested(DelegatedValidationEventArgs args)
{
    var handler = this.ValidationRequested;
    if (handler == null) {
        return;
    }

    foreach (EventHandler<DelegatedValidationEventArgs> target in handler.GetInvocationList()) {
        target.Invoke(this, args);
        if (args.Handled) {
            break;
        }
    }
}

所以工作流程如下:

  1. 当模型即将被视图模型包装时,可以执行验证的某个适当实体会订阅其ValidationRequested事件。
  2. 视图与模型绑定;在某些时候,验证被触发。
  3. 模型调用GetValidationError
  4. 逐个调用事件处理程序;产生验证错误的第一个处理程序将args.ValidationErrorargs.Handled设置为true,以便链被停止。
  5. 验证错误将返回到视图。
  6. 如果视图模型需要知道其模型是否有效(例如,启用/禁用“保存”命令),还需要进入此过程。

    无法无法对IDataErrorInfo / INotifyDataErrorInfo做任何事情,因为您如何实施它们完全取决于您。对于更多示例,请务必查看后者文档的Silverlight version;互联网上还有很多有用的资料like this