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
Youre le seul qui comprennent comment laid quand un code de ligne forcé tour dans le code 9 lignes. – nyconing