TextBox with validation loses ErrorTemplate on tab change

前端 未结 3 1635
孤街浪徒
孤街浪徒 2020-12-05 04:22

I have a TextBox with a validation rule that is on a tab of a TabControl. The default ErrorTemplate correctly shows (red border around TextBox) when the validation rule fail

3条回答
  •  借酒劲吻你
    2020-12-05 04:46

    As Dylan explained, this is because the Adorner layer, in which the validation errors are drawn, is discarded on tab switch. So you need to wrap the content with AdornerDecorator.

    I have created a behavior that wraps the Content of TabItem automatically in an AdornerDecorator, so that it doesn't have to be done manually on all TabItems.

    public static class AdornerBehavior
    {
        public static bool GetWrapWithAdornerDecorator(TabItem tabItem)
        {
            return (bool)tabItem.GetValue(WrapWithAdornerDecoratorProperty);
        }
        public static void SetWrapWithAdornerDecorator(TabItem tabItem, bool value)
        {
            tabItem.SetValue(WrapWithAdornerDecoratorProperty, value);
        }
    
        // Using a DependencyProperty as the backing store for WrapWithAdornerDecorator.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WrapWithAdornerDecoratorProperty =
            DependencyProperty.RegisterAttached("WrapWithAdornerDecorator", typeof(bool), typeof(AdornerBehavior), new UIPropertyMetadata(false, OnWrapWithAdornerDecoratorChanged));
    
        public static void OnWrapWithAdornerDecoratorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var tabItem = o as TabItem;
            if (tabItem == null) return;
    
            if(e.NewValue as bool? == true)
            {
                if (tabItem.Content is AdornerDecorator) return;
                var content = tabItem.Content as UIElement;
                tabItem.Content = null;
                tabItem.Content = new AdornerDecorator { Child = content };
            }
            if(e.NewValue as bool? == false)
            {
                if (tabItem.Content is AdornerDecorator)
                {
                    var decorator= tabItem.Content as AdornerDecorator;
                    var content = decorator.Child;
                    decorator.Child = null;
                    tabItem.Content = content;
                }
            }
        }
    }
    

    You can set this behavior on all TabItems via a default style:

    
    

    b is the namespace where the behavior is located, something like this (will be different for every project):

    xmlns:b="clr-namespace:Styling.Behaviors;assembly=Styling"
    

提交回复
热议问题