Confessions of a .NET Developer!

Give underline effect to a textbox in WPF using Adorners

Shahin had a question, he wanted to give an underline to a textbox when it recieves focus. You can see it here: Question.

I pondered for a while and thought why not use an Adorner. An Adorner will simple place a layer(here a line) on the textbox. Adorners won’t disturb the control. It will just decorate over the control. The idea is, whenever the textbox gets focus, add the adorner and when it loses the focus, remove it. Here is the solution that I provided to Shahin: Solution
Here is a nice introduction to Adorners: Adorners

Let’s get started. First create a WPF Application named Adorners.
Then create a class named AdornOnTextBox which will inherit the Adorner class.
It looks something like this:

using System.Windows.Documents;
using System.Windows;
using System.Windows.Media;

namespace Adornerss
{
    class AdornOnTextBox : Adorner
    {
        public Brush UnderlineBrush { get; set; }
        public double UnderlineThickness { get; set; }

        public AdornOnTextBox(UIElement adornedElement, Brush _underlineBrush, double _underlineThickness)
            : base(adornedElement)
        {
            UnderlineBrush = _underlineBrush;
            UnderlineThickness = _underlineThickness;
        }

        protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
        {
            //Provides area around the AdornedElement(here, TextBox) where the adorner will be used.
            Rect adornedElementRect = new Rect(AdornedElement.RenderSize);

            //Draw over the control using the Pen.
            Pen pen = new Pen(UnderlineBrush, UnderlineThickness);

            //We will draw the line from bottom-left to bottom right ___________
            drawingContext.DrawLine(pen, adornedElementRect.BottomLeft, adornedElementRect.BottomRight);
        }
    }
}

Wondering why I overrode the OnRender method? The textbox undergoes a series of layout measurements while doing arranging and measuring passes. So it is safe to apply the adorner only after these passes are performed and OnRender is the place to do it. For complex cases, you might want to override ArrangeOverride and MeasureOverride methods but that will be beyond the scope of this article.

Next in the window, add a textbox and name it txtBox.
And then do this:

using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace Adornerss
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        //Create a reference object for AdornOnTextBox
        AdornOnTextBox adornIt;

        //Create a reference object for AdornerLayer
        AdornerLayer adornLayer;

        public Window1()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Window1_Loaded);

            // Attach the event handlers.
            txtBox.GotFocus += new RoutedEventHandler(txtBox_GotFocus);
            txtBox.LostFocus += new RoutedEventHandler(txtBox_LostFocus);
        }

        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            //Instantiation
            adornIt = new AdornOnTextBox(txtBox, Brushes.Red, 2);

            //Get the AdornerLayer of our TextBox.
            adornLayer = AdornerLayer.GetAdornerLayer(txtBox);
        }

        void txtBox_GotFocus(object sender, RoutedEventArgs e)
        {
            //Add the adorner
            adornLayer.Add(adornIt);
        }

        void txtBox_LostFocus(object sender, RoutedEventArgs e)
        {
            //Remove the adorner
            adornLayer.Remove(adornIt);
        }
    }
}

The code is self-explanatory.

And here is our final result:

GotFocus

GotFocus

LostFocus

LostFocus

I have also used a button so that, when the button is clicked, the focus on the textbox will be lost and so will be the Red underline.
That’s it!

There is also another solution provided by nit-singh. Solution 2
But it won’t give you the exact underline but worth giving it a try if you want a XAML only solution. I have edited his answer a bit to show the underline more clear.

Happy coding!

Advertisements

July 4, 2011 Posted by | C Sharp, WPF | 2 Comments