2

I am trying to create a masked textbox to have a border colors.

I tried this below code to achieve it:

public class MaskedTextBoxWithBorder : UserControl
{
    MaskedTextBox maskedtextBox;

    public MaskedTextBoxWithBorder()
    {
        maskedtextBox = new MaskedTextBox()
        {
            BorderStyle = BorderStyle.FixedSingle,
            Location = new Point(-1, -1),
            Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
        };
        Control container = new ContainerControl()
        {
            Dock = DockStyle.Fill,
            Padding = new Padding(-1)
        };
        container.Controls.Add(maskedtextBox);
        this.Controls.Add(container);

        DefaultBorderColor = SystemColors.ControlDark;
        FocusedBorderColor = Color.Red;
        BackColor = DefaultBorderColor;
        Padding = new Padding(1);
        Size = maskedtextBox.Size;
    }

    public Color DefaultBorderColor { get; set; }
    public Color FocusedBorderColor { get; set; }

    public override string Text
    {
        get
        {
            return maskedtextBox.Text;
        }
        set
        {
            maskedtextBox.Text = value;
        }
    }

    protected override void OnEnter(EventArgs e)
    {
        BackColor = FocusedBorderColor;
        base.OnEnter(e);
    }

    protected override void OnLeave(EventArgs e)
    {
        BackColor = DefaultBorderColor;
        base.OnLeave(e);
    }

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {
        base.SetBoundsCore(x, y, width, maskedtextBox.PreferredHeight, specified);
    }
}

But the problem is it does not have the all features of the masked text box like setting mask type etc.

So I changed my code like this:

public class MaskedTextBoxWithBorder : UserControl

Now I have all features of Masked text box but border colors are not affected.

Is there any way to extend Masked textbox to get border style without losing features something like this which is not possible.

public class MaskedTextBoxWithBorder : UserControl, MaskedTestBox
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Nithin B
  • 601
  • 1
  • 9
  • 26

3 Answers3

2

TextBox and MaskedTextBox controls are only wrappers of Win32 TextBox controls so owner drawing them (for custom borders, overlays or anything else) is a bit more complex than normally. Here's what you should do to achieve what you're trying to do.

  1. Derive from MaskedTextBox: public class MaskedTextBoxWithBorder : MaskedTextBox
  2. Get access to the message stream for the Win32 TextBox (it draws itself in response to multiple messages so you need to catch them all, not just the standard WM_PAINT message).
  3. Get the handle to the device context and transform it into a managed Graphics object to draw the border.

Take a look at the following article that explains each step in detail: Adding an Icon or Control to a TextBox or ComboBox

Even though the article discusses the basic TextBox control, it doesn't matter. Both TextBox and MaskedTextBox derive from the TextBoxBase class, which implements all the important parts we're interested in.

Timo Salomäki
  • 7,099
  • 3
  • 25
  • 40
  • The border is drawn in non-client area and the only message which you need to handle to draw border with custom color is `WM_NCPAINT`. – Reza Aghaei Sep 17 '16 at 04:55
2

To draw border of MaskedTextBox you should override WndProc and handle WM_NCPAINT message. Then get the window dc of the control and create a Graphics object from that dc, then draw border for control.This solution has been used also in ToolStripTextBox. The solution can be applied also on a TextBox.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyMaskedTextBox : MaskedTextBox
{
    public const int WM_NCPAINT = 0x85;
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_NCPAINT)
        {
            var hdc = GetWindowDC(this.Handle);
            using (var g = Graphics.FromHdcInternal(hdc))
            {
                g.DrawRectangle(Pens.Blue, new Rectangle(0, 0, Width - 1, Height - 1));
            }
            ReleaseDC(this.Handle, hdc);
        }
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Also to see how to change the focused border color take a look at [this post](http://stackoverflow.com/a/38405319/3110834) – Reza Aghaei Sep 09 '16 at 13:23
  • Also [here](http://stackoverflow.com/a/39420512/3110834) is an example of how to add `BorderColor` property for `TextBox`. – Reza Aghaei Sep 20 '16 at 11:47
  • It seems the post answers your question and it would be great if you accept the answer. Otherwise let me know if you have any problem applying the answer. Also make sure you take a look at [linked post](http://stackoverflow.com/a/39420512/3110834) which contains a complete implementation of `BorderColor` property. – Reza Aghaei Oct 13 '16 at 07:43
  • Thanks for the feedback, you can see a more completed version containing `BorderColor` in [this post](http://stackoverflow.com/a/39420512/3110834). – Reza Aghaei Nov 22 '16 at 12:22
0

Well, usually in a given application, you only change a few property so you might simply add some extra property to your user control for those properties you want to be able to change.

public class MaskedTextBoxWithBorder : UserControl
{
    MaskedTextBox maskedtextBox;

    // Other existing code...

    public string Mask
    {
        get { return maskedtextBox.Mask; }
        set { maskedtextBox.Mask = value; }
    }

    // Do same thing for other properties you want to change...
}

If you really want to change a lot of properties, then other solutions might be more appropriate...

Phil1970
  • 2,605
  • 2
  • 14
  • 15