WPF DataBinding监视抛出的异常

时间:2009-11-05 15:47:21

标签: c# wpf data-binding exception-handling

在我的模型中,我有很多不同对象的属性,我在设置对象的值时检查值,如果值不被接受,我将抛出一个异常,这对Windows窗体的属性很好,但现在我'我试图使用WPF设计一个新的界面。 在WPF中,当我将属性绑定到像文本框这样的控件时,当值更改时,我不知道如何处理异常并显示错误消息。 例如:

public string  ConnectionString
        {
            get
            {
                return (_ConnectionString);
            }
            set
            {
                try
                {
                    _ConnectionString  = value ;
                    _SqlConnection = new System.Data.SqlClient.SqlConnection(_ConnectionString);
                    _ConnectionTested = true;
                }
                catch (Exception caught)
                {
                    _ConnectionTested = false;
                    _TableNameTested = false;
                    _FieldNameTested = false;
                    _ConditionTested = false;
                    _ConnectionString = "";
                    //----delete values----
                    ValuesCollection.Clear();
                    throw (new Exception("Can not Open the connection String \nReason : " + caught.Message )); 
                }
            }
        }

和wpf部分类似:

<TextBox TextWrapping="Wrap" x:Name="ConnectionStringTextBox" Text="{Binding Path=ConnectionString, Mode=TwoWay}"/>
无论如何,当文本框中的值被更改时,

是否存在检查模型是否抛出异常,然后向用户显示exception.message?

感谢

2 个答案:

答案 0 :(得分:5)

Kent使用ValidationRule和ExceptionValidationRule是完全正确的。但是,你会发现这个解决方案非常不愉快,因为你有很多绑定到这样的字段的情况。在许多地方,你将取代这样的东西:

<TextBox Text="{Binding Value}" />

用这个:

<TextBox Validation.ErrorTemplate="{StaticResource errorTemplate}">
  <TextBox.Text>
    <Binding Path="Value">
      <Binding.ValidationRules>
        <ExceptionValidationRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

因为这是如此笨拙,我喜欢创建一个自动应用验证规则的继承附加属性,所以我要说的是:

<Window
  ValidationHelper.ErrorTemplate="{StaticResource errorTemplate}"
...
   <TextBox Text="{Binding Value}" />
   <TextBox Text="{Binding OtherValue}" />

我的附属属性会自动对窗口中的每个绑定应用验证,因此各个文本框不必担心验证。

要做到这一点,我使用这个一般技术:

  public class ValidationHelper : DependencyObject
  {
    [ThreadStatic]
    static List<DependencyObject> _objectsNeedingValidationUpdate;

    public static ControlTemplate GetErrorTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(ErrorTemplateProperty); }
    public static void SetErrorTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(ErrorTemplateProperty, value); }
    public static readonly DependencyProperty ErrorTemplateProperty = DependencyProperty.RegisterAttached("ErrorTemplate", typeof(ControlTemplate), typeof(ValidationHelper), new FrameworkPropertyMetadata
    {
      Inherits = true,
      PropertyChangedCallback = (obj, e) =>
        {
          if(e.NewValue)
            if(_objectsNeedingValidationUpdate!=null)
              _objectsNeedingValidationUpdate.Add(obj);
            else
            {
              _objectsNeedingValidationUpdate = new List<DependencyObject>();
              _objectsNeedingValidationUpdate.Add(obj);
              Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new Action(UpdateValidations));
            }
        },
    });

    static void UpdateValidations()
    {
      List<DependencyObject> objects = _objectsNeedingValidationUpdate;
      _objectsNeedingValidationUpdate = null;
      if(objects!=null)
        foreach(DependencyObject obj in objects)
          UpdateValidations(obj);
    }
    static void UpdateValidations(DependencyObject obj)
    {
      // My regular code uses obj.GetLocalValueEnumerator here, but that would require some other complexity
      if(UpdateValidations(obj, TextBox.TextProperty))
        if(Validation.GetErrorTemplate(obj)==null)
          Validation.SetErrorTemplate(obj, ValidationHelper.GetErrorTemplate(obj));
    }
    static bool UpdateValidations(DependencyObject obj, DependencyProperty prop)
    {
      var binding = BindingOperations.GetBinding(obj, prop);
      if(binding!=null &&
        binding.Mode==BindingMode.TwoWay &&
        !binding.ValidationRules.Any(rule => rule is ExceptionValidationRule))
      {
        binding.ValidationRules.Add(new ExceptionValidationRule());
        BindingOperations.SetBinding(obj, prop, binding);  // Required to get new rule to work
        return true;
      }
      return false;
    }
  }

有关如何创建errorTemplate资源的示例,请参阅Validation类的MSDN文档。另请注意:

  • 我的ValidationHelper类不会阻止您设置自定义Validation.ErrorTemplate值 单个TextBoxes。这些将覆盖ValidationHelper.ErrorTemplate。
  • 您可以轻松添加对TextBox以外的控件和Text
  • 以外的属性的支持

答案 1 :(得分:3)

看看binding validationBinding类有一个ValidationRules集合,您可以在其中添加ExceptionValidationRule