cost
cost

Reputation: 4490

Need more control over a textbox's MouseDown and KeyDown

The title is only somewhat accurate. I'm trying to do something special with a textbox and the lack of certain events firing is causing some trouble, but I'd also like some general advice of how to do what it is I'm trying to do here. I'm trying to recreate a special textbox that exists on an old access application. It's for entering in a social security number, and when blank it displays ___-__-____.

When you click on any of the spaces it highlights the particular character. If you enter a number, it replaces the _ with that number. If you hit delete or backspace, it just replaces whatever character is highlighted with an _ or a -, depending.

I can sort of recreate this by having a textbox that is readonly and firing a PreviewMouseUp event to call a method that highlights the current cursor position. But since it's readonly it won't fire any KeyUp or KeyDown events to alter the selection. I can get it to do that if I put a KeyUp in the main UI grid, but it only works on KeyUp, so it winds up looking very laggy. Same issue with the PreviewMouseUp, I want it to highlight when the mouse is pressed down, not up, but PreviewMouseDown fires nothing.

I feel like I'm going about this in a messier and messier way. I've described what I want, does anyone have any better ideas of how to accomplish this that isn't super complicated? I want to keep the textbox readonly to allow me to handle the key inputs manually. What I mean is, My original way of formatting this was to simply run a method on KeyUp which checked the length of what you added and format it appropriately (add dashes, etc), but that results in this moment where everything looks unformatted until you release the key. For example, if I press '2' in the middle of the textbox it shifts all of the dashes over by a character until the '2' button is released, and then the formatting is fixed.

Thoughts?

Upvotes: 2

Views: 563

Answers (2)

Mark Hall
Mark Hall

Reputation: 54562

What you are describing is known as a Masked Textbox. There is a free one in the VisualStudioGallery and in the Extended WPF ToolKit

Upvotes: 0

cost
cost

Reputation: 4490

It's funny how long I'd been working on this for now to finally get it, but the key was in AddHandler. For those of you who want a textbox like this, here's how I did it. There's a few messy bits in here, and those are simply to recreate the exact functionality of the access textbox. The most annoying part was implementing the backspace button, since it deletes what's before the selected section. Also, make sure your textbox is IsReadOnly.

In the constructor put:

textBox_ssn.AddHandler(Control.MouseDownEvent, new MouseButtonEventHandler(ClickSS), true);
textBox_ssn.AddHandler(Control.KeyDownEvent, new KeyEventHandler(ButtonSS), true);

Then use these two methods:

public void ClickSS(object sender, EventArgs e)
    {
        textBox_ssn.SelectionLength = 1;
    }

    public void ButtonSS(object sender, KeyEventArgs e)
    {
        bool on_first_char = false;
        if (textBox_ssn.SelectionStart == 0) on_first_char = true;

        if (e.Key == Key.Right && textBox_ssn.SelectionStart < 10)
        {
            ++textBox_ssn.SelectionStart;
            textBox_ssn.SelectionLength = 1; //Without this, it will move around large blocks of selection
            if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
        }
        else if (e.Key == Key.Left && textBox_ssn.SelectionStart > 0)
        {
            --textBox_ssn.SelectionStart;
            textBox_ssn.SelectionLength = 1;
            if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
        }
        else
        {
            string temp = "";
            switch (e.Key)
            {
                case Key.D0:
                    temp = "0";
                    break;
                case Key.D1:
                    temp = "1";
                    break;
                case Key.D2:
                    temp = "2";
                    break;
                case Key.D3:
                    temp = "3";
                    break;
                case Key.D4:
                    temp = "4";
                    break;
                case Key.D5:
                    temp = "5";
                    break;
                case Key.D6:
                    temp = "6";
                    break;
                case Key.D7:
                    temp = "7";
                    break;
                case Key.D8:
                    temp = "8";
                    break;
                case Key.D9:
                    temp = "9";
                    break;
                case Key.Delete:
                    temp = "_";
                    break;
                case Key.Back:
                    temp = "_";
                    if (textBox_ssn.SelectionStart > 0) --textBox_ssn.SelectionStart;
                    if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
                    //else return; //or could do temp = selection text but only if selection length is 1 ectect
                    break;
            }

            if (temp != "")
            {
                if (textBox_ssn.SelectionLength > 1)
                {
                    string underscores = "";

                    foreach (char c in textBox_ssn.SelectedText)
                    {
                        if (c == '-') underscores += "-";
                        else underscores += "_";
                    }

                    textBox_ssn.SelectedText = underscores;
                    textBox_ssn.SelectionLength = 1;
                }

                if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
                if (textBox_ssn.SelectionLength == 1)
                {
                    if (!(on_first_char && e.Key == Key.Back)) textBox_ssn.SelectedText = temp;

                    if (e.Key == Key.Delete) ;
                    else if (e.Key == Key.Back)
                    {
                        if (textBox_ssn.SelectionStart > 0)
                        {
                            //--textBox_ssn.SelectionStart;
                            if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
                        }
                    }
                    else
                    {
                        ++textBox_ssn.SelectionStart;
                        if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
                    }
                }
            }
        }
    }

Upvotes: 1

Related Questions