WPF DataBinding监视抛出的异常

Ash*_*sha 4 c# data-binding wpf 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 )); 
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

和wpf部分是这样的:

<TextBox TextWrapping="Wrap" x:Name="ConnectionStringTextBox" Text="{Binding Path=ConnectionString, Mode=TwoWay}"/>
Run Code Online (Sandbox Code Playgroud)

无论如何,当文本框中的值更改时,检查模型是否抛出异常,然后向用户显示exception.message?

谢谢

Ray*_*rns 5

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

<TextBox Text="{Binding Value}" />
Run Code Online (Sandbox Code Playgroud)

有了这个:

<TextBox Validation.ErrorTemplate="{StaticResource errorTemplate}">
  <TextBox.Text>
    <Binding Path="Value">
      <Binding.ValidationRules>
        <ExceptionValidationRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>
Run Code Online (Sandbox Code Playgroud)

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

<Window
  ValidationHelper.ErrorTemplate="{StaticResource errorTemplate}"
...
   <TextBox Text="{Binding Value}" />
   <TextBox Text="{Binding OtherValue}" />
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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