benPearce
benPearce

Reputation: 38333

Position the caret in a MaskedTextbox

I would like to be able to override the default behaviour for positioning the caret in a masked textbox.

The default is to place the caret where the mouse was clicked, the masked textbox already contains characters due to the mask.

I know that you can hide the caret as mentioned in this post, is there something similar for positioning the caret at the beginning of the textbox when the control gets focus.

Upvotes: 22

Views: 24680

Answers (9)

Joelius
Joelius

Reputation: 4329

I know this is an old question but google has led me here multiple times and none of the answers do exactly what I want.
For example, the current answers don't work as I want when you're using TextMaskFormat = MaskFormat.ExcludePromptAndLiterals.

The method below makes the cursor jump to the first prompt when the textbox is entered. Once you've entered the textbox, you can freely move the cursor. Also it works fine for MaskFormat.ExcludePromptAndLiterals.

That's why I think it's worth leaving this here :)

private void MaskedTextBox_Enter(object sender, EventArgs e)
{
    // If attached to a MaskedTextBox' Enter-Event, this method will
    // make the cursor jump to the first prompt when the textbox gets focus.
    if (sender is MaskedTextBox textBox)
    {
        MaskFormat oldFormat = textBox.TextMaskFormat;
        textBox.TextMaskFormat = MaskFormat.IncludePromptAndLiterals;
        string fullText = textBox.Text;
        textBox.TextMaskFormat = oldFormat;

        int index = fullText.IndexOf(textBox.PromptChar);
        if (index > -1)
        {
            BeginInvoke(new Action(() => textBox.Select(index, 0)));
        }
    }
}

Upvotes: 1

Bill Kamer
Bill Kamer

Reputation: 1

This solution uses the Click method of the MaskedTextBox like Gman Cornflake used; however, I found it necessary to allow the user to click inside the MaskedTextBox once it contained data and the cursor stay where it is.

The example below turns off prompts and literals and evaluates the length of the data in the MaskedTextBox and if equal to 0 it puts the cursor at the starting position; otherwise it just bypasses the code that puts the cursor at the starting position.

The code is written in VB.NET 2017. Hope this helps!

Private Sub MaskedTextBox1_Click(sender As Object, e As EventArgs) Handles MaskedTextBox1.Click
    Me.MaskedTextBox1.TextMaskFormat = MaskFormat.ExcludePromptAndLiterals
    If Me.MaskedTextBox1.Text.Length = 0 Then
        MaskedTextBox1.Select(0, 0)
    End If
    Me.MaskedTextBox1.TextMaskFormat = MaskFormat.IncludePromptAndLiterals
End Sub

Upvotes: 0

Gman Cornflake
Gman Cornflake

Reputation: 11

I got mine to work using the Click event....no Invoke was needed.

 private void maskedTextBox1_Click(object sender, EventArgs e)
{
     maskedTextBox1.Select(0, 0);              
}

Upvotes: 0

hmota
hmota

Reputation: 388

This solution works for me. Give it a try please.

private void maskedTextBox1_Click(object sender, EventArgs e)
{

 maskedTextBox1.Select(maskedTextBox1.Text.Length, 0);
}

Upvotes: 0

Brian Pressman
Brian Pressman

Reputation: 31

//not the prettiest, but it gets to the first non-masked area when a user mounse-clicks into the control
private void txtAccount_MouseUp(object sender, MouseEventArgs e)
{
  if (txtAccount.SelectionStart > txtAccount.Text.Length)
    txtAccount.Select(txtAccount.Text.Length, 0);
}

Upvotes: 3

Mike M
Mike M

Reputation: 71

That is a big improvement over the default behaviour of MaskedTextBoxes. Thanks!

I made a few changes to Ishmaeel's excellent solution. I prefer to call BeginInvoke only if the cursor needs to be moved. I also call the method from various event handlers, so the input parameter is the active MaskedTextBox.

private void    maskedTextBoxGPS_Click( object sender, EventArgs e )
{
    PositionCursorInMaskedTextBox( maskedTextBoxGPS );
}


private void    PositionCursorInMaskedTextBox( MaskedTextBox mtb )
{
  if (mtb == null)    return;

  int pos = mtb.SelectionStart;

  if (pos > mtb.Text.Length)
    this.BeginInvoke( (MethodInvoker)delegate()  { mtb.Select( mtb.Text.Length, 0 ); });
}

Upvotes: 7

Abbas
Abbas

Reputation: 6886

This should do the trick:

    private void maskedTextBox1_Enter(object sender, EventArgs e)
    {
        this.BeginInvoke((MethodInvoker)delegate()
        {
            maskedTextBox1.Select(0, 0);
        });         
    }

Upvotes: 34

Ishmaeel
Ishmaeel

Reputation: 14373

To improve upon Abbas's working solution, try this:

private void ueTxtAny_Enter(object sender, EventArgs e)
{
    //This method will prevent the cursor from being positioned in the middle 
    //of a textbox when the user clicks in it.
    MaskedTextBox textBox = sender as MaskedTextBox;

    if (textBox != null)
    {
        this.BeginInvoke((MethodInvoker)delegate()
        {
            int pos = textBox.SelectionStart;

            if (pos > textBox.Text.Length)
                pos = textBox.Text.Length;

            textBox.Select(pos, 0);
        });
    }
}

This event handler can be re-used with multiple boxes, and it doesn't take away the user's ability to position the cursor in the middle of entered data (i.e does not force the cursor into zeroeth position when the box is not empty).

I find this to be more closely mimicking a standard text box. Only glitch remaining (that I can see) is that after 'Enter' event, the user is still able to select the rest of the (empty) mask prompt if xe holds down the mouse and drags to the end.

Upvotes: 10

mdb
mdb

Reputation: 52819

Partial answer: you can position the caret by assigning a 0-length selection to the control in the MouseClick event, e.g.:

MaskedTextBox1.Select(5, 0)

...will set the caret at the 5th character position in the textbox.

The reason this answer is only partial, is because I can't think of a generally reliable way to determine the position where the caret should be positioned on a click. This may be possible for some masks, but in some common cases (e.g. the US phone number mask), I can't really think of an easy way to separate the mask and prompt characters from actual user input...

Upvotes: 3

Related Questions