Search code examples
wpfxamlcontroltemplatecontentpresentervalidationrule

Why textbox border red color appears on the panel over textbox


I am under a situation where i have textbox which has to do some validation, Upon validation it show red color border. The problem is when i hover a panel over the unvalidated textbox, the red color border is still visible on the panel which is over the textbox, even if the panel has full opacity, Its probably a WPF textbox bug.

I have the code below to produce this problem: Xaml:

<Window x:Class="RedTextBoxFix.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:RedTextBoxFix"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Margin="5">
        <Canvas Panel.ZIndex="6000" Name="panel2" Margin="5">
            <Expander Background="LightGray" ExpandDirection="Right" 
                      Header="Expand over the textbox.." 
                      VerticalAlignment="Top" 
                      HorizontalAlignment="Left">
                <StackPanel Width="900" Height="600">
                </StackPanel>
            </Expander>
        </Canvas>
        <StackPanel Name="panel1" Visibility="Visible" Margin="5">
            <TextBox Name="DataBoundTextBox" Height="20" Width="100" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Binding Path="TextValue">
                    <Binding.ValidationRules>
                        <ExceptionValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox>
        </StackPanel>
    </StackPanel>
</Window>

Code of file:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace RedTextBoxFix
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new MyClass("RemoveThisText");



        }
        public class MyClass : INotifyPropertyChanged
        {

            private string mTextValue;

            public MyClass(string defaultText)
            {
                TextValue = defaultText;
            }

            public string TextValue
            {
                get
                {
                    return mTextValue;
                }
                set
                {
                    mTextValue = value;
                    if (string.IsNullOrEmpty(mTextValue))
                    {
                        throw new ApplicationException("Text value cannot be empty");
                    }
                    OnPropertyChanged(new PropertyChangedEventArgs("TextValue"));
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;

            protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, e);
                }
            }
        }
    }
}

Production steps :

(1) Copy paste code in WPF project and then lauch application.

(2) Remove entire text and press tab and then you have red border of textbox

(3) Expand the Expander.

Now you have unexpected red border over the expander panel. Which is has to be removed. But how ? Thats the question, Any help please ?


Solution

  • An Adorner is a custom FrameworkElement that is bound to a UIElement. Adorners are rendered in an AdornerLayer, which is a rendering surface that is always on top of the adorned element or a collection of adorned elements.

    Among other things, adorners are used to provide visual feedback, error in your case. Window has an AdornerDecorator which is on top of everything, and it contains an AdornerLayer. That is where your adorner which indicates an error is rendered. So you'll need one underneath the Canvas, you can just add one around the TextBox.

    <StackPanel Name="panel1" Visibility="Visible" Margin="5">
        <AdornerDecorator>
            <TextBox Name="DataBoundTextBox" Height="20" Width="100" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Binding Path="TextValue">
                    <Binding.ValidationRules>
                        <ExceptionValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox>
        </AdornerDecorator>
    </StackPanel>
    

    More details on adorners on Microsoft Docs.