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 值
单独的文本框。这些将覆盖 ValidationHelper.ErrorTemplate。
- 您可以轻松添加对 TextBox 以外的控件和 Text 以外的属性的支持