2009-11-05 11 views
3

Dans mon modèle j'ai beaucoup de propriétés pour différents objets et je vérifie la valeur tout en définissant la valeur de l'objet et si la valeur n'est pas acceptée, je vais lancer une exception cela fonctionne parfaitement avec Windows forms propertygrid mais maintenant j'essaye de concevoir une nouvelle interface en utilisant WPF. dans WPF lorsque je lie une propriété à un contrôle comme zone de texte, lorsque la valeur est modifiée, je ne sais pas comment gérer l'exception et afficher le message d'erreur. exemple:WPF DataBinding montre pour les exceptions levées

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

et la partie de WPF est comme:

<TextBox TextWrapping="Wrap" x:Name="ConnectionStringTextBox" Text="{Binding Path=ConnectionString, Mode=TwoWay}"/> 

est là de toute façon lorsque la valeur saisie est changé vérifier si le modèle a jeté une exception, puis montrer l'Exception.Message à utilisateur?

grâce

Répondre

3

Jetez un oeil à binding validation. La classe Binding a une collection ValidationRules, à laquelle vous pouvez ajouter un ExceptionValidationRule.

5

Kent a absolument raison d'utiliser ValidationRule et ExceptionValidationRule. Cependant, vous trouverez cette solution très désagréable à utiliser pour votre situation où vous avez beaucoup de liaisons à des champs comme celui-ci. Dans de nombreux endroits que vous remplacerez quelque chose comme ceci:

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

avec ceci:

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

Parce que cela est si difficile à manier, je souhaite créer une propriété attachée héritée qui applique automatiquement les règles de validation, de sorte que tous Je dois dire est:

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

Ma propriété jointe applique automatiquement la validation à chaque fixation dans la fenêtre, de sorte que les zones de texte individuelles ne doivent pas inquiéter abo ut validation.

Pour ce faire, j'utiliser cette techinique générale:

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

Voir la documentation MSDN de la classe de validation pour un exemple de la façon de créer votre ressource ErrorTemplate. Notez également que:

  • classe Mon ValidationHelper ne vous empêche pas de définir des valeurs de Validation.ErrorTemplate personnalisées sur TextBoxes individuels. Ceux-ci remplaceront le ValidationHelper.ErrorTemplate.
  • Vous pouvez facilement ajouter le support pour les contrôles autres que TextBox et propriétés autres que le texte
+0

Youre le seul qui comprennent comment laid quand un code de ligne forcé tour dans le code 9 lignes. – nyconing