Suppress backspace, delete keys in MaskedTextbox - c#

The question is simple: how to do it?
I've a couple of MaskedTextboxes which are filled by some indirect user actions (so not by typing in values directly). The text within the textboxes is colored red when the input is being rejected by the mask. Fine so far.
However, I don't want the end-user to be able to edit the boxes directly. So, I added the following code:
private void HandleMaskedTextBoxKeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void HandleMaskedTextBoxKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
e.SuppressKeyPress = true;
}
And while most characters are handled, the backspace and delete keys aren't: text disappears when pressing those keys. How can those keys be handled, too?
(Another option would be to set the readonly property of the boxes to true, but then the text doesn't get colored red anymore when input is rejected. I tried to force the red color in the MaskInputRejected event, but this didn't work out, either.)

I think it's a good idea to set the MaskedTextBox's ReadOnly property to true. But instead of handling the MaskInputRejected event, you should use the TypeValidationCompleted event like this:
private void maskedTextBox1_TypeValidationCompleted(object sender, TypeValidationEventArgs e) {
maskedTextBox1.ForeColor = e.IsValidInput ? Color.Black : Color.Red;
}
Since I guess you're modifying the value of the MaskedTextBox by code, you'll have to also handle the TextChanged event to trigger a validation like this:
private void maskedTextBox1_TextChanged(object sender, EventArgs e) {
maskedTextBox1.ValidateText();
}
Finally (and this is key), since the MaskedTextBox will be read only, you'll want to set the BackColor and ForeColor properties back to Color.White and Color.Black respectively, but you'll have to do it in code, in the constructor of the form for instance...
maskedTextBox1.BackColor = Color.White;
maskedTextBox1.ForeColor = Color.Black;
If you have a lot of them, I suggest you create a new control that inherits from MasketTextBox and override those values.

You can use a richtextbox. Set read only to true, and mask the chars with the code beind.
I hope that helps.
RG

Related

DataGridView MaskedTextBoxColumn

I have a DataGridView, and I would like to have something similar to a MaskedTextBox inside my DataGridView. It doesn't have to be an exact MaskedTextBox, but at least somewhat acting like one.
Here is what my DataGridView looks like.
All I want is that the people who modify the DataGridView's right column (Durée - 'Duration'), follow the Mask pattern 00:00:00 for time.
Another solution would be to place a DateTimePicker. But similar to the solution using a MaskedTextBox, it does supposedly not exist as DataGridView columns.
I have tried using the Column's Builder to add a Behavior→Format, but I don't think this is quite the same. I need something to prevent the user from adding random stuff.
You have (at least) two options:
You can use a regular MaskedTextBox overlaid over the TextBox the DGV creates for editing
You can code the regular edit control, i.e. the TextBox the DGV shows when entering edit mode.
Here are examples for both:
First we create class level variables for the controls:
TextBox editBox = new TextBox();
MaskedTextBox editMBox = new MaskedTextBox();
To get a reference to the editing textbox we code the EditingControlShowing event:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
editBox = e.Control as TextBox;
}
To control user input we hook up the KeyPress event:
public Form1()
{
InitializeComponent();
..
editBox.KeyPress += editBox_KeyPress;
..
}
Here we can do all sorts of check and prevent bad characters from entering. All the regular properties are there..:
void editBox_KeyPress(object sender, KeyPressEventArgs e)
{
string sNew = editBox.Text.Substring(0, editBox.SelectionStart)
+ e.KeyChar + editBox.Text.Substring(editBox.SelectionStart);
Console.WriteLine(sNew);
e.Handled = !validateMethod(sNew);
}
This would call a function you can write..
But if you are happy with what a MaskedTextBox you can simply use one:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
DataGridViewCell cell = dataGridView1.CurrentCell;
editMBox.Parent = dataGridView1;
editMBox.Location = dataGridView1.GetCellDisplayRectangle(cell.ColumnIndex,
cell.RowIndex, false).Location;
editMBox.Size = editBox.Size;
editMBox.Show();
editMBox.Mask = yourMask;
editMBox.BringToFront();
}
We need to hook up the KeyPress event for the MaskedTextBox to end to editing. Here is just a simple way to accept the value when Enter is pressed.
You will want to handle Esc here and also at least the CurrentCellChanged event for more complete control..
void editMBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
editBox.Text = editMBox.Text;
editMBox.Hide();
}
}
I found this neat little program MaskedTextBoxColumn in DataGridViews. I had found that a little earlier, but was reluctant to download it since we had to register and stuff. Actually worked out pretty well. The mask properties is a little too simple, as it is lacking some nice features, but the general MaskedTextBox idea is there.

How to set TextBox to only accept numbers?

I have already checked other questions here but the answers are not related to my issue. the following code allows textbox1 to only accept numbers if the physical keyboard (laptop) is pressed:
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
char ch = e.KeyChar;
if ( !char.IsDigit(ch))
{
e.Handled = true;
}
}
but this is not what I wanted (I dont use physical laptop keyboard).
As shown in screenshot, I have windows form with buttons and a textbox. I designed this keyboard and it works well but I want textbox1 to only accept numbers and the ".".
There are only two lines of code inside each button (and only code in the project) which is:
private void buttonName_Click(object sender, EventArgs e)
{
// each button only has this code.
textBox1.Focus();
SendKeys.Send(buttonName.Text);
}
I know how to set txtbox to accept numbers if the physical (laptop ) keys are pressed but here in this case I have control buttons in windwos form and I want to set textBox1 to only accept numbers and the ".". Please help in how to achieve this. Thank you
Declare a string variable at form level, use it to store the last valid text and to restore it when an invalid text is entered on the TextChanged event of your textbox.
string previousText;
public Form1()
{
InitializeComponent();
previousText = String.Empty;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
int dummy, changeLenght, position;
if (!String.IsNullOrWhiteSpace(textBox1.Text) && !int.TryParse(textBox1.Text, out dummy))
{
position = textBox1.SelectionStart;
changeLenght = textBox1.TextLength - previousText.Length;
textBox1.Text = previousText;
textBox1.SelectionStart = position - changeLenght;
}
else
{
previousText = textBox1.Text;
}
}
position and changeLenght are used to keep the cursor where it was before restoring the text.
In case you want to accept numbers with decimals or something bigger than 2147483647, just change dummy to double and use double.TryParse instead of int.TryParse.
private void textBox1_TextChanged(object sender, EventArgs e)
{
int changeLenght, position;
double dummy;
if (!String.IsNullOrWhiteSpace(textBox1.Text) && !double.TryParse(textBox1.Text, out dummy))
{
...
}
}
Suppose button1 is your button control, you could do this:
private void allButtons_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
char c = btn.Text[0]; //assuming all buttons have exactly 1 character
if(Char.IsDigit(c) || c == '.')
{
//process
textBox1.Focus();
SendKeys.Send(btn.Text);
}
//otherwise don't
}
I'm assuming you put this in a common handler, to which you already wired all your buttons (i.e. allButtons_Click).
Problem with this approach, it allows you to type values like 0.0.1, which are most likely invalid in your context. Another way to handle this is to process TextChanged event, store previous value, and if new value is invalid, restore the old one. Unfortunately, TextBox class does not have TextChanging event, which could be a cleaner option.
The benefit of you determining the invalid value is modularity. For example, if you later decide your user can enter any value, but only numbers can pass validation, you could move your check from TextChanged to Validate button click or similar.
Why users may want that - suppose one of the options for input is copy/paste - they want to paste invalid data and edit it to become valid, for example abc123.5. If you limit them at the entry, this value will not be there at all, so they now need to manually paste into Notepad, cut out in the invalid characters, and paste again, which goes against productivity.
Generally, before implementing any user interface limitation, read "I won't allow my user to...", think well, whether it's justified enough. More often than not, you don't need to limit the user, even for the good purpose of keeping your DB valid etc. If possible, never put a concrete wall in front of them, you just need to guide them correctly through your workflow. You want users on your side, not against you.

Setting a ReadOnly TextBox default BackColor

I have a TextBox which is set to be ReadOnly.
At some point that TextBox is being available for editing, and it's BackColor changes (It is indicating if the value is valid).
If I want to set the TexBox back to ReadOnly, the TextBox doesn't get back the original BackColor that a ReadOnly TextBox gets.
What should I do in order to get the original color again?
I realize I can set the color manually to SystemColors.Control, but is this the "right way"?
Code Sample
This is a simple code for demonstration.
If SystemColors.Control is the way to go, I will change it in the ReadOnlyChanged event...
private void button1_Click(object sender, EventArgs e)
{
//At this point this.textBox1 is ReadOnly
this.textBox1.ReadOnly = false;
this.textBox1.BackColor = Color.Orange;
/*this.textBox1.BackColor = SystemColors.Control;*/ //Is this the right way?
this.textBox1.ReadOnly = true; //Textbox remains orange...
}
You have to set BackColor to the look of a ReadOnly TextBox's BackColor, that is Color.FromKnownColor(KnownColor.Control):
//this is the ReadOnlyChanged event handler for your textbox
private void textBox1_ReadOnlyChanged(object sender, EventArgs e){
if(textBox1.ReadOnly) textBox1.BackColor = Color.FromKnownColor(KnownColor.Control);
}
You may need a variable to store the current BackColor every time your TextBox's BackColor changes:
Color currentBackColor;
bool suppressBackColorChanged;
private void textBox1_BackColorChanged(object sender,EventArgs e){
if(suppressBackColorChanged) return;
currentBackColor = textBox1.BackColor;
}
private void textBox1_ReadOnlyChanged(object sender, EventArgs e){
suppressBackColorChanged = true;
textBox1.BackColor = textBox1.ReadOnly ? Color.FromKnownColor(KnownColor.Control) : currentBackColor;
suppressBackColorChanged = false;
}
I know this is an old question, but for posterity sake:
TextBox as well as many other controls rely on Color.Empty to decide whether or not to display its default color.
To set a TextBox back to the system default (irregardless of state):
textBox1.BackColor = Color.Empty;
Yes, that's fine. There's no reason you can't use the SystemColors to specify the desired color for the control. I've never heard of anything in WinForms that would cause a control to automatically revert to its default color upon setting ReadOnly = true.
I suppose one alternative is to create a class-level variable called textBox1OriginalColor or something and set it in the form's Load event. Then you know exactly what it was when the form was originally displayed, if you think someone might in the future set the text box's default background color to, say, blue in the designer or something.

How to detect if an event is sent by an argument

I don't know if it is called an argument (i.e. textbox1.text = "Hello";).
I have a control and there is a text box in it. It has a dropdown box that opens when the text is changed. But when I update the text in the text box that box drops down.
I need a way to make it so it only drops down if someone manually does it.
TBAddressBar.ABText.Text = getCurrentBrowser().Source.ToString();
and
public void ABText_TextChanged(object sender, TextChangedEventArgs e)
{
if (sender == 1*)
{
ABDropDown.Visibility = Visibility.Visible;
}
else
{
ABDropDown.Visibility = Visibility.Collapsed;
}
}
If someone manually does it, presumably they are using keypresses to do so. In that case, use KeyDown or KeyUp events to show the dropdown instead.
What I have done in the past is use a boolean variable that I set when I update my textboxes programically to bypass the TextChangedEvent.
i.e.
bool loading;
....
loading =true;
TBAddressBar.ABText.Text = getCurrentBrowser().Source.ToString();
loading = false;
public void ABText_TextChanged(object sender, TextChangedEventArgs e)
{
if(loading) return;
....
}
Simple, just remove the code from your TextChanged Event.
Anyway you got the basic idea.. Now do your dropdown logic in KeyPress event, since it accepts only characters and not the modifiers. So it behaves closer to your requirement. Not that you cant handle the same using KeyDown and KeyUp, you can, but more code..

How to disable cursor in textbox?

Is there any way to disable cursor in textbox without setting property Enable to false?
I was trying to use ReadOnly property but despite the fact that I can't write in textbox, the cursor appears if I click the textbox. So is there any way to get rid of this cursor permamently?
In C#, you can use the following read-only textbox:
public class ReadOnlyTextBox : TextBox
{
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
public ReadOnlyTextBox()
{
this.ReadOnly = true;
this.BackColor = Color.White;
this.GotFocus += TextBoxGotFocus;
this.Cursor = Cursors.Arrow; // mouse cursor like in other controls
}
private void TextBoxGotFocus(object sender, EventArgs args)
{
HideCaret(this.Handle);
}
}
In C# you can disable the cursor in a textbox by temporarily disabling and then re-enabling the text box whenever it receives the focus. Note there is no need to make the textbox read only if using this method. For example:
private void TextBox_Enter(object sender, EventArgs e)
{
TextBox.Enabled = false;
TextBox.Enabled = true;
}
You could use a Label instead. When in the designer, you set BorderStyle = Fixed3D, BackColor = Window and AutoSize = False, it looks a lot like a TextBox.
However, the cursor in a TextBox is provided so that the user can scroll through the text when it is longer than the box. You'll lose that functionality with a Label, unless you are sure that it will always fit. Other than that, it is not possible to remove the cursor from a TextBox.
Putting the hideCaret function inside the TextChanged event will solve the problem:
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
private void textBox1_TextChanged(object sender, EventArgs e)
{
HideCaret(textBox1.Handle);
}
Easiest solution for me was to just override the on focus event and focus back to the parent. This prevents the cursor and any editing of the textbox by the user and basically disables the text box with out having to set the Enabled = false property.
private void Form1_load(object sender, EventArgs e) {
textBox1.ReadOnly = true;
textBox1.Cursor = Cursors.Arrow;
textBox1.GotFocus += textBox1_GotFocus;
}
private void textBox1_GotFocus(object sender, EventArgs e) {
((TextBox)sender).Parent.Focus();
}
Like #Mikhail Semenov 's solution, you can also use lambda express to quickly disable the cursor if you do not have many textboxes should do that:
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
textBox1.ReadOnly = true;
textBox1.BackColor = Color.White;
textBox1.GotFocus += (s1, e1) => { HideCaret(textBox1.Handle); };
textBox1.Cursor = Cursors.Arrow;
You can set it programatically.
textBox1.Cursor = Cursors.Arrow;
This is not strictly an answer to the question, but perhaps it can solve some similar problem(s). I use a textbox control which can look like a label for a control which displays a scale, but can be edited, when clicked. Start enabled = false and make an activation (enabled = true) in a mousehandler of the parent of the textbox control (which, when disabled, border None and backcolor = parent backcolor, looks like a label). E.g. when enter hit or other event, disable again in KeyDown handler.
(Of course the parent mouse click routine can check whether the mouseclick really occured in the label/textbox control).
If you need the textbox control to activate by tabbing, some more work is required (than I have done).
I use the form constructor to find the textbox parent at runtime and to apply the delegate mouse control. Perhaps you can do this as wel in compile time (Form header), but that seemed a little error-prone to me.
One way of doing it is using View + TabIndex, you can do indexing of some other controls on the dialog as first, let say for buttons if there any. Then as if the control tabIndex is not the first i.e 0, cursor won't get appear there.
To disable the edit and cursor in the TEXT BOX
this.textBox.ReadOnly = true;
this.textBox.Cursor = Cursors.No;//To show a red cross icon on hover
this.textBox.Cursor = Cursors.Arrow //To disable the cursor
you can use RightToLeft Property of Text Box, set it to true, you will not get rid of the Cursor, but it will get fixed at right corner and it will not appear automatically after every text you type in your text Box. I have used this to develop an application like Windows Calculator.

Categories