Reputation: 38333
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
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
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
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
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
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
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
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
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
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