How to limit textbox to accept only specific characters - c#

I wanted to know How to limit number of specific character of a textbox in c# form application.
for example i want to limit the user to enter - (minus) only one time and then if he try to input again I want the program to restrict inputing that again.
Examples: -123 or 123- or 123-123 (only one -).
If user remove - then should have permission to input one - again and of course no more!
I want to prevent user to enter ----1234 or 1234--, or 123-4--21 or what more you think!!
Here is what I'm trying:
private void txtStopAfterXTimes_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.OemMinus || e.KeyCode == Keys.Subtract)
{
if (txtStopAfterXTimes.Text.Count((char)'-', 1))
{
e.SuppressKeyPress = true;
}
else if (txtStopAfterXTimes.Text.Count((char)'-', 0))
{
e.SuppressKeyPress = false;
}
}
}
i know it's wrong but please help!
thank you...

You can change the Text within txtStopAfterXTimes by 2 ways: pressing a key (-) or by pasting a value.
That's why we have to handle 2 events: KeyPress for - key pressing and TextChanged for text pasting:
Code: (WinForms)
private void txtStopAfterXTimes_TextChanged(object sender, EventArgs e) {
// When pasting a text into txtStopAfterXTimes...
TextBox box = sender as TextBox;
StringBuilder sb = new StringBuilder(box.Text.Length);
bool containsMinus = false;
// We remove all '-' but the very first one
foreach (char ch in box.Text) {
if (ch == '-') {
if (containsMinus)
continue;
containsMinus = true;
}
sb.Append(ch);
}
box.Text = sb.ToString();
}
private void txtStopAfterXTimes_KeyPress(object sender, KeyPressEventArgs e) {
TextBox box = sender as TextBox;
// we allow all characters ...
e.Handled = e.KeyChar == '-' && // except '-'
box.Text.Contains('-') && // when we have '-' within Text
!box.SelectedText.Contains('-'); // and we are not going to remove it
}

I'd avoid using TextChanged because it will be raised after the text has changed and it may be a bit late.
This is the solution which I will use, because you also need to care about paste.
On keyPress I check if the character is not the first "-", then I'll ignore it, otherwise I'll accept it.
On WndProc I catch WM_PASTE and sanitize the clipboard text, by removing all occurrences of "-" but the first one. You can also easily decide to stop pasting if the input is not acceptable.
Here is the implementation:
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyTextBox : TextBox
{
private const int WM_PASTE = 0x0302;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool MessageBeep(int type);
protected override void WndProc(ref Message m)
{
if (m.Msg != WM_PASTE) { base.WndProc(ref m); }
else {
//You can sanitize the input or even stop pasting the input
var text = SanitizeText(Clipboard.GetText());
SelectedText = text;
}
}
protected virtual string SanitizeText(string value)
{
if (Text.IndexOf('-') >= 0) { return value.Replace("-", ""); }
else {
var str = value.Substring(0, value.IndexOf("-") + 1);
return str + value.Substring(str.Length).Replace("-", "");
}
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (e.KeyChar == '-' && this.Text.IndexOf('-') >= 0) {
e.Handled = true;
MessageBeep(0);
}
else {
base.OnKeyPress(e);
}
}
}

Related

Why are numeric keystrokes appearing twice?

I'm new to C#. Using the code below, whenever I press a number key on my keyboard, it will display twice in the textbox. When I press "1" on the keyboard it will display
"11", and when I press "2" it will display "22". Why is this?
private void Window_TextInput(object sender, TextCompositionEventArgs e)
{
if(!isNumeric(e.Text))
{
string display = string.Empty;
display += e.Text;
displayNum(display);
}
else
{
String inputOperator = string.Empty;
inputOperator += e.Text;
if (inputOperator.Equals("+"))
{
ApplySign(sign.addition, "+");
}
}
}
private bool isNumeric(string str)
{
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex("[^0-9]");
return reg.IsMatch(str);
}
private void window_keyUp(object sender, KeyEventArgs e)
{
if (e.Key >= Key.D0 && e.Key <= Key.D9)
{
int num = e.Key - Key.D0;
outputText2.Text += num;
}
}
private void BtnNum_Click(object sender, RoutedEventArgs e)
{
Button num = ((Button)sender);
displayNum(num.Content.ToString());
}
private void displayNum(String n)
{
if (operator1 == 0 && double.Parse(n) == 0)
{
}
else
{
if (operator1 == 0)
{
outputText2.Clear();
}
outputText2.Text += n;
operator1 = double.Parse(outputText2.Text);
outputText2.Text = Convert.ToString(operator1);
}
}
You have two events that are handeling the Keyboard events. Although not really sure what the displayNum() method is doing
I am assuming the Window_TextInput event is the event you wish to primarily handle the event.
Try adding
e.Handled = true;
In the Window_TextInput method. If that doesn't solve the problem can you post the displayNum() method?
EDIT:
After further review of the code and trying the same I do not see the relevance for the window_keyUp method as your Window_TextInput handles the input characters and has more applicable logic for handling the TextInput changes.
After I removed the window_keyUp event method the output appeared as expected (although commented out the ApplySign() method.
You've subscribed to two window-level text-related events - TextInput and KeyUp - and both of them end up appending input to the TextBox.
window_keyUp appends numbers to the TextBox
It looks like Window_TextInput is supposed to append non-numeric characters, but your RegEx is incorrect ([^0-9] matches anything that is not numeric, so IsNumeric returns True if the input is not a number)
The effect is that every numeric key press shows up twice.

Remove String from Text Box from back

I have a requirement in C# where I have a text box with numbers delimited by ; say e.g.
(205)33344455;918845566778;
Now when a user presses ← Backspace (to remove the number) one character at a time gets deleted. I want to delete the whole number at once.
So when the user presses ← the first time, the number will be highlighted
i.e. if text is (205)33344455;918845566778;, the 918845566778; part will be highlighted in say black, and when the user presses ← again the whole number i.e. 918845566778; will be deleted.
So is it possible to highlight a particular section in text box, and delete the whole number?
I used a for loop like:
for{back=txtPhone.Text.Length;back<=txtPhone.Text.indexOf(';');back--)
But I was not able to achieve the desired result.
Any help on this would be great.
You can implement your requirement as shown below
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (textBox1.Text.Length == 0) return;
if ((e.KeyChar == (char)Keys.Back) && (textBox1.SelectionLength == 0))
{
textBox1.SelectionStart = Math.Max(0, textBox1.Text.Substring(0,textBox1.Text.Length-1).LastIndexOf(';'));
if (textBox1.Text.Substring(textBox1.SelectionStart, 1) == ";") textBox1.SelectionStart++;
textBox1.SelectionLength = textBox1.Text.Length-textBox1.SelectionStart ;
e.Handled = true;
return;
}
if ((e.KeyChar == (char)Keys.Back) && textBox1.SelectionLength >= 0)
{
textBox1.Text = textBox1.Text.Substring(0, textBox1.SelectionStart );
textBox1.SelectionStart = textBox1.Text.Length;
e.Handled = true;
}
}
A couple of methods to achieve want you want come to mind:
Subscribing the text box to Control.Keydown event which would check for the ← button and perform the highlight up to the last delimiter (;) using TextBox.SelectionLength meaning a ← Backspace will clear it.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode != Keys.Left)
return;
e.SuppressKeyPress = true;
//Select up to previous delimeter (;) here
}
Use a listbox (or something similar) to store the delimited data as it is entered. This will allow the user to select what they need, and remove it via a button you will provide.
You can :
Select the token (i.e. number terminated by ;) that contains the cursor (method selectToken())
Remove it when backspace is
pressed a second time
Example:
your textbox contains '(205)33344455; 918845566778; 8885554443;'
you click with the left mouse button between 9188455 and 66778; (second number)
then you press backspace
the string 918845566778; gets selected
you press backspace a second time and that string gets deleted
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Remove_String_from_Text_Box_from_back
{
public partial class Form1 : Form
{
//selects token that contains caret/cursor
private void selectToken() {
string str0 = textBox1.Text;
int caretPosition = textBox1.SelectionStart;
int tokenEndsAtIndex = str0.IndexOf(';', caretPosition, (textBox1.Text.Length - caretPosition));
string prefix = "";
if (tokenEndsAtIndex == -1)
{
tokenEndsAtIndex = str0.IndexOf(';');
}
prefix = str0.Substring(0, tokenEndsAtIndex);
int tokenStartsAtIndex = 0;
tokenStartsAtIndex = prefix.LastIndexOf(';');
if (!(tokenStartsAtIndex > -1)) { tokenStartsAtIndex = 0; } else { tokenStartsAtIndex++; }
textBox1.SelectionStart = tokenStartsAtIndex;
textBox1.SelectionLength = tokenEndsAtIndex - tokenStartsAtIndex + 1;//may be off by one
}
private void selectLastToken(string str0)
{
Regex regex = new Regex(#"([\d()]*;)$");
var capturedGroups = regex.Match(str0);
int idx0 = 0;
if (capturedGroups.Captures.Count > 0)
{
idx0 = str0.IndexOf(capturedGroups.Captures[0].Value, 0);
textBox1.Select(idx0, textBox1.Text.Length);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = "(205)33344455;918845566778;";
textBox1.Select(0, 0);
}
//selects last token terminated by ;
private void selectTextOnBackSpace()
{
string str0 = textBox1.Text;
int idx0 = str0.LastIndexOf(';');
if (idx0<0)
{
idx0 = 0;
}
string str1 = str0.Remove(idx0);
int idx1 = str1.LastIndexOf(';');
if (idx1 < 0)
{
idx1 = 0;
}
else
{
idx1 += 1;
}
textBox1.SelectionStart = idx1;
textBox1.SelectionLength = str0.Length - idx1;
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Back )
{
if (textBox1.SelectionLength==0)
{
selectToken();
e.Handled = true;
}
else
{
e.Handled = false;
}
}
}
}
}

Permanent prefix in a TextBox

I am trying to have a permanent prefix input in the textbox. In my case, I want to have the following prefix:
DOMAIN\
So that users can only have to type their username after the domain prefix. It's not something I have to do, or pursue but my question is more out of curiosity.
I was trying to come up with some logic to do this on the TextChangedEvent however, this means I need to know which characters have been deleted where and then pre-append DOMAIN\ to whatever their input is - I can't work out the logic for this so I can't post what I have tried apart from where I got to.
public void TextBox1_TextChanged(object sender, EventArgs e)
{
if(!TextBox1.Text.Contains(#"DOMAIN\")
{
//Handle putting Domain in here along with the text that would be determined as the username
}
}
I've looked on the internet and can't find anything, How do I have text in a winforms textbox be prefixed with unchangable text? was trying to do a similar thing but the answers don't really help.
Any ideas on how I can keep the prefix DOMAIN\ in a TextBox?
Using the KISS principle is indicated here. Trying to catch key presses just won't do anything when the user uses Ctrl+V or the context menu's Cut and Paste commands. Simply restore the text when anything happened that fudged the prefix:
private const string textPrefix = #"DOMAIN\";
private void textBox1_TextChanged(object sender, EventArgs e) {
if (!textBox1.Text.StartsWith(textPrefix)) {
textBox1.Text = textPrefix;
textBox1.SelectionStart = textBox1.Text.Length;
}
}
And help the user avoid editing the prefix by accident:
private void textBox1_Enter(object sender, EventArgs e) {
textBox1.SelectionStart = textBox1.Text.Length;
}
Why not see in the event args of the textChanged what the value was before and the new value and if the Domain\ is not there in the new value, then keep the old one.
Or, why not just show the Domain\ as a label in front of the TextBox and just prepend it in code behind so that the final text is something like Domain\<username>.
Yeah I sort of solved this once I asked the question... I won't delete the question incase anybody else has the same question in the future, because I couldn't find a suitable answer. I set the Text to Domain\ and then used the KeyPress event.
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = (textBox1.GetCharIndexFromPosition(Cursor.Position) < 7);
}
I tend to keep working once I ask, instead of letting people do all the work for me :)
How about a reusable custom TextBox control. There are comments in the code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.Prefix = #"DOMAIN\";
}
}
class PrefixedTextBox : TextBox
{
private string _prefix = String.Empty;
public string Prefix
{
get { return _prefix; }
set
{
_prefix = value;
Text = value;
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
// Don't allow Backspace and Delete if the only text is Prefix
if (Text == Prefix && (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete))
e.Handled = true;
// If home key is pressed set cursor just after the prefix
if (e.KeyCode == Keys.Home)
{
e.Handled = true;
SelectionStart = Prefix.Length;
}
// Don't allow cursor to be moved inside Prefix
if (SelectionStart <= Prefix.Length && (e.KeyCode == Keys.Left || e.KeyCode == Keys.Up))
e.Handled = true;
base.OnKeyDown(e);
}
protected override void OnClick(EventArgs e)
{
EnsureCursorPosition();
base.OnClick(e);
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
EnsureCursorPosition();
// this was checked OnKeyDown. This prevents deleting and writing back behaviour
if (Text == Prefix && e.KeyChar == '\b')
e.Handled = true;
base.OnKeyPress(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
// Yet, some how an invalid text is entered fix it by just displaying the Prefix
if (!Text.StartsWith(Prefix))
Text = Prefix;
base.OnKeyUp(e);
}
private void EnsureCursorPosition()
{
// Never allow cursor position before Prefix
if (SelectionStart < Prefix.Length)
SelectionStart = Text.Length;
}
}

Check window for focus-Password Generator C#

For my end of year project I am creating a password generator where you generate a password, then you can choose whether or not you want to store it in a local compact DB(.sdf). I am working on the GUI at the moment. I am creating a strength bar for passwords but the problem is that I can't seem to have it update the strength bar without first moving the slider. Let me show you example of what I am talking about. I was wondering if I could do this with code or with action events. Tell me what you think. Below is some code for the GUI designer. Do you think this is a good idea or would there be a better way? The focus idea came from if the window has focus it would keep checking the options and see if anything has changed. Video: http://youtu.be/ihSeKbsL55M
namespace PasswordGenerator
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void fileToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void quitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void quitToolStripMenuItem1_Click(object sender, EventArgs e)
{
this.Close();
}
private void bcopy_Click(object sender, EventArgs e)
{
if (passwordGenBox.Text.Length != 0)
{
Clipboard.SetText(passwordGenBox.Text);
}
else
{
MessageBox.Show("No Password Generated.", "Copy Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void bclear_Click(object sender, EventArgs e)
{
passwordGenBox.Text = "";
}
private void lengthSlider_Scroll(object sender, EventArgs e)
{
sliderLength.Text = lengthSlider.Value.ToString();
int str = lengthSlider.Value;
bool scheck = symCheck.Checked;
bool ncheck = numbersCheck.Checked;
//1-10 no symbols or numbers
if (str > 0 && str <= 10)
{
strLabel.Text = "Week";
}
//1-10 symbols no numbers
if (str > 0 && str <= 10 && scheck == true && ncheck == false)
{
strLabel.Text = "Alright";
}
//1-10 no symbols but numbers
if (str > 0 && str <= 10 && scheck == false && ncheck == true)
{
strLabel.Text = "Week";
}
//1-10 symbols & numbers
if (str > 0 && str <= 10 && scheck == true && ncheck == true)
{
strLabel.Text = "Okay";
}
}
private void bgen_Click(object sender, EventArgs e)
{
int pwlength = lengthSlider.Value;
bool symbols = false;
bool numbers = false;
if (symCheck.Checked && numbersCheck.Checked)
{
symbols = true;
numbers = true;
}
else if (symCheck.Checked && numbersCheck.Checked == false)
{
symbols = true;
numbers = false;
}
else if (symCheck.Checked == false && numbersCheck.Checked)
{
symbols = false;
numbers = true;
}
else
{
symbols = false;
numbers = false;
}
Generator gen = new Generator(pwlength, symbols, numbers);
}
}
}
Well, it's quite difficult to understand what you're actually asking here but the reason your ProgressBar isn't updating is that you're not actually telling it to update unless you move the slider.
Notice how you have all your logic for whether the password is "alright, weak or okay" on the Slide event of your "lengthSlider" component. However, nowhere in that code do you set the value of the ProgressBar - that appears to be done on the "bgen_Click" event which I assume is the generate password button?
In order to update the GUI when you operate the individual controls you need to call the appropriate code. I would suggest you put all your logic into meaningful functions and call them as needed.
Personally I'd have something along these lines:
GetPasswordStrengthString(); - check for symbols and numbers checkbox.checked and the length to return an appropriate string for the "strLabel" label.
CalculateStrengthBarLength(); - all your logic to determine the length of the ProgressBar
These would then be called wherever you want them to take effect. For example, on the CheckedChanged event of the symbols and numbers checkboxes as when that changes you want to see it reflected in the ProgressBar.

Autocomplete AND preventing new input - combobox

How can I allow the users of my program to type in a value and have it auto-complete, however, I also what to prevent them from entering new data because it would cause the data to be unfindable (unless you had direct access to the database).
Does anyone know how to do this?
The reasoning behind not using just a dropdown style combobox is because entering data by typing it is and then refusing characters that are not part of an option in the list is because it's easier on the user.
If you have used Quickbook's Timer, that is the style of comboboxes I am going for.
Kudos to BFree for the help, but this is the solution I was looking for. The ComboBox is using a DataSet as it's source so it's not a custom source.
protected virtual void comboBoxAutoComplete_KeyPress(object sender, KeyPressEventArgs e) {
if (Char.IsControl(e.KeyChar)) {
//let it go if it's a control char such as escape, tab, backspace, enter...
return;
}
ComboBox box = ((ComboBox)sender);
//must get the selected portion only. Otherwise, we append the e.KeyChar to the AutoSuggested value (i.e. we'd never get anywhere)
string nonSelected = box.Text.Substring(0, box.Text.Length - box.SelectionLength);
string text = nonSelected + e.KeyChar;
bool matched = false;
for (int i = 0; i < box.Items.Count; i++) {
if (((DataRowView)box.Items[i])[box.DisplayMember].ToString().StartsWith(text, true, null)) {
matched = true;
break;
}
}
//toggle the matched bool because if we set handled to true, it precent's input, and we don't want to prevent
//input if it's matched.
e.Handled = !matched;
}
This is my solution, I was having the same problem and modify your code to suit my solution using textbox instead of combobox, also to avoid a negative response after comparing the first string had to deselect the text before comparing again against autocomplet list, in this code is an AutoCompleteStringCollection shiper, I hope this solution will help
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
String text = ((TextBox)sender).Text.Substring(
0, ((TextBox)sender).SelectionStart) + e.KeyChar;
foreach(String s in this.shippers)
if (s.ToUpperInvariant().StartsWith(text.ToUpperInvariant()) ||
e.KeyChar == (char)Keys.Back || e.KeyChar == (char)Keys.Delete)
return;
e.Handled = true;
}
OK, here's what I came up with. Hack? Maybe, but hey, it works. I just filled the combobox with the days of the week (hey, I needed something), and then handle the keypress event. On every key press, I check if that word matches the begining of any word in the AutoCompleteSourceCollection. If it doesn't, I set e.Handled to true, so the key doesn't get registered.
public Form5()
{
InitializeComponent();
foreach (var e in Enum.GetValues(typeof(DayOfWeek)))
{
this.comboBox1.AutoCompleteCustomSource.Add(e.ToString());
}
this.comboBox1.KeyPress += new KeyPressEventHandler(comboBox1_KeyPress);
}
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
string text = this.comboBox1.Text + e.KeyChar;
e.Handled = !(this.comboBox1.AutoCompleteCustomSource.Cast<string>()
.Any(s => s.ToUpperInvariant().StartsWith(text.ToUpperInvariant()))) && !char.IsControl(e.KeyChar);
}
EDIT: If you're on .Net 3.5 you'll need to reference System.Linq. If you're on .NET 2.0 then use this instead:
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
string text = this.comboBox1.Text + e.KeyChar;
foreach (string s in this.comboBox1.AutoCompleteCustomSource)
{
if (s.ToUpperInvariant().StartsWith(text.ToUpperInvariant()))
{
return;
}
}
e.Handled = true;
}
I know I'm about six years late but maybe this can help somebody.
private void comboBox1_Leave(object sender, EventArgs e)
{
if (comboBox1.Items.Contains(comboBox1.Text)) { MessageBox.Show("YE"); }
else { MessageBox.Show("NE"); }
OR
if (comboBox1.FindStringExact(comboBox1.Text) > -1) { MessageBox.Show("YE"); }
else { MessageBox.Show("NE"); }
}

Categories