Question

I have a textbox that should disallow entering any special characters.

The user can enter :

  1. A-Z
  2. a-z
  3. 0-9
  4. Space

How can I make the KeyDown event to do this?

Was it helpful?

Solution

private void _txtPath_KeyDown(object sender, KeyEventArgs e)
  {
     if ((e.Key < Key.A) || (e.Key > Key.Z))
        e.Handled = true;
  }

OTHER TIPS

Handling the KeyDown or KeyPress events is one way to do this, but programmers usually forget that a user can still copy-and-paste invalid text into the textbox.

A somewhat better way is to handle the TextChanged event, and strip out any offending characters there. This is a bit more complicated, as you have to keep track of the caret position and re-set it to the appropriate spot after changing the box's Text property.

Depending on your application's needs, I would just let the user type in whatever they want, and then flag the textbox (turn the text red or something) when the user tries to submit.

Just wanted to add some code for those ending up here by search:

private void Filter_TextChanged(object sender, EventArgs e)
{
    var textboxSender = (TextBox)sender;
    var cursorPosition = textboxSender.SelectionStart;
    textboxSender.Text = Regex.Replace(textboxSender.Text, "[^0-9a-zA-Z ]", "");
    textboxSender.SelectionStart = cursorPosition;
}

This is a change filter, so handles copy and paste, and preserves cursor position so that changing text in the middle works properly.

Note it uses the 'sender' to get the control name, allowing this one function to be linked to multiple textbox boxes, assuming they need the same filter. You can link multiple controls by going to the event section of a control and manually picking the function for the TextChanged event.

Use a regex to filter out the other characters. Or use Char.IsDigit, IsXXX methods to filter out unwanted characters. Lots of ways to do this.

Update: If you must use KeyDown then it seems that you need to also handle KeyPressed and set obEventArgs.Handled = true to disallow the characters. See the example on the KeyDown MSDN Page

Update: Now that you specify it's WPF. The below code will allow only a-z and A-Z characters to be entered into the textbox. Extend as needed...

private void _txtPath_KeyDown(object sender, KeyEventArgs e)
      {
         if ((e.Key < Key.A) || (e.Key > Key.Z))
            e.Handled = true;
      }

This will break if you copy-paste stuff into the text-box. Validate the entire text once the user leaves the control or when he clicks OK/Submit as MusicGenesis says.

I think it's worth considering doing the filtering on the TextBox's TextChanged event. You can create an operation that gets rid of any non-valid characters from your text string. This is a bit more messy than blocking the KeyDown event.

But, I think this is the way to go because you are not blocking WPF's built-in KeyDown/Up event handling mechanisms, so copy/paste still works. You would be working at a higher level of abstractions so I think it will be easier to figure out what is going on.

I ran into this in silverlight and wrote something like this.

private string _filterRegexPattern = "[^a-zA-Z0-9]"; // This would be "[^a-z0-9 ]" for this question.
private int _stringMaxLength = 24;


private void _inputTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    if (!string.IsNullOrEmpty(_filterRegexPattern))
    {
        var text = _inputTextBox.Text;
        var newText = Regex.Replace(_inputTextBox.Text, _filterRegexPattern, "");

        if (newText.Length > _stringMaxLength)
        {
            newText = newText.Substring(0, _stringMaxLength);
        }


        if (text.Length != newText.Length)
        {
            var selectionStart = _inputTextBox.SelectionStart - (text.Length - newText.Length);
            _inputTextBox.Text = newText;
            _inputTextBox.SelectionStart = selectionStart;
        }
    }
}

I accomplish this with a custom Dependency Property. It's reusable for any TextBox control, is much faster and more efficient to use than building key events, and makes my code files much cleaner.

In addition, it can handle other input methods which does not trigger key events, such as pasting a value into the TextBox using the mouse.

The code for the custom DP looks like this:

// When set to a Regex, the TextBox will only accept characters that match the RegEx

/// <summary>
/// Lets you enter a RegexPattern of what characters are allowed as input in a TextBox
/// </summary>
public static readonly DependencyProperty AllowedCharactersRegexProperty =
    DependencyProperty.RegisterAttached("AllowedCharactersRegex",
                                        typeof(string), typeof(TextBoxProperties),
                                        new UIPropertyMetadata(null, AllowedCharactersRegexChanged));

// Get
public static string GetAllowedCharactersRegex(DependencyObject obj)
{
    return (string)obj.GetValue(AllowedCharactersRegexProperty);
}

// Set
public static void SetAllowedCharactersRegex(DependencyObject obj, string value)
{
    obj.SetValue(AllowedCharactersRegexProperty, value);
}

// Events
public static void AllowedCharactersRegexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var tb = obj as TextBox;
    if (tb != null)
    {
        if (e.NewValue != null)
        {
            tb.PreviewTextInput += Textbox_PreviewTextChanged;
            DataObject.AddPastingHandler(tb, TextBox_OnPaste);
        }
        else
        {
            tb.PreviewTextInput -= Textbox_PreviewTextChanged;
            DataObject.RemovePastingHandler(tb, TextBox_OnPaste);
        }
    }
}

public static void TextBox_OnPaste(object sender, DataObjectPastingEventArgs e)
{
    var tb = sender as TextBox;

    bool isText = e.SourceDataObject.GetDataPresent(DataFormats.Text, true);
    if (!isText) return;

    var newText = e.SourceDataObject.GetData(DataFormats.Text) as string;
    string re = GetAllowedCharactersRegex(tb);
    re = string.Format("[^{0}]", re);

    if (Regex.IsMatch(newText.Trim(), re, RegexOptions.IgnoreCase))
    {
        e.CancelCommand();
    }
}

public static void Textbox_PreviewTextChanged(object sender, TextCompositionEventArgs e)
{
    var tb = sender as TextBox;
    if (tb != null)
    {
        string re = GetAllowedCharactersRegex(tb);
        re = string.Format("[^{0}]", re);

        if (Regex.IsMatch(e.Text, re, RegexOptions.IgnoreCase))
        {
            e.Handled = true;
        }
    }
}

And it's used like this:

<TextBox Text="{Binding SomeValue, UpdateSourceTrigger=PropertyChanged}" 
         local:TextBoxHelpers.AllowedCharactersRegex="a-zA-Z0-9\s" />

I know that winForms have available a MaskedTextBox control, which lets you specify exactly this sort of thing. I don't know WPF, so I dunno if that's available there, but if it is, do that. Its MUCH easier than all this stuff with keypresses and events, and more robust too.

The easiest way to do this would be to included the Extended WPF Toolkit which has a control for doing exactly what you are asking for by specifying a mask.

http://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox&referringTitle=Home

It will also display the mask in the text box as you are inputting if required.

(It also has many other useful controls)

and your regExp could look like [0-9a-zA-Z]* to allow only English alphanumeric chracters

only alphanumeric TextBox WPF C#,

sorry for my english.. but with this code for WPF, c#, I only permit alphanumeric

private void txtTraslado_TextChanged(object sender, KeyEventArgs e)
{
  if (((e.Key < Key.NumPad0)||(e.Key > Key.NumPad9))&&((e.Key < Key.A)||(e.Key > Key.Z)))
  {
    e.Handled = true;
  }
}

Use Asp.NET AJAX Control Toolkit

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

And Use FilteredTextBoxExtender

<asp:TextBox ID="txt_gpf_no" runat="server" CssClass="textbox" 
                                                MaxLength="10"></asp:TextBox>
<asp:FilteredTextBoxExtender ID="FilteredTextBoxExtender_gpf_no" runat="server" Enabled="True"
                                                TargetControlID="txt_gpf_no" FilterType="UppercaseLetters,LowercaseLetters,Custom" ValidChars="1234567890 ">
</asp:FilteredTextBoxExtender>

in my.Net Framework 4.5 C# application

    private void txtRF_Register_Val_KeyDown(object sender, KeyEventArgs e)
    {
        //only enable alphanumeric
        if (!(((e.KeyCode < Keys.NumPad0) || (e.KeyCode > Keys.NumPad9)) && ((e.KeyCode < Keys.A) || (e.KeyCode > Keys.E))))
        {
            e.SuppressKeyPress = false;
        }
        else
        {
            e.SuppressKeyPress = true;
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top