[C#] 숫자 만 허용하는 텍스트 상자를 만들려면 어떻게합니까?

정수 값만 허용하려는 텍스트 상자 컨트롤이있는 Windows Forms 앱이 있습니다. 과거에는 KeyPress 이벤트를 오버로드하고 사양에 맞지 않는 문자를 제거하여 이러한 종류의 유효성 검사를 수행했습니다. MaskedTextBox 컨트롤을 살펴 보았지만 정규 표현식으로 작동하거나 다른 컨트롤의 값에 의존 할 수있는보다 일반적인 솔루션을 원합니다.

숫자가 아닌 문자를 누르면 결과가 생성되지 않거나 사용자에게 유효하지 않은 문자에 대한 피드백을 즉시 제공하는 것이 이상적입니다.



답변

두 가지 옵션 :

  1. NumericUpDown대신 사용하십시오 . NumericUpDown은 필터링 기능을 제공합니다. 물론 사용자가 키보드의 위쪽 및 아래쪽 화살표를 눌러 현재 값을 늘리거나 줄일 수 있습니다.

  2. 숫자 입력 이외의 다른 것을 방지하려면 적절한 키보드 이벤트를 처리하십시오. 표준 TextBox 에서이 두 이벤트 핸들러로 성공했습니다.

    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&
            (e.KeyChar != '.'))
        {
                e.Handled = true;
        }
    
        // only allow one decimal point
        if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
        {
            e.Handled = true;
        }
    }
    

TextBox에서 소수점 이하 자릿수를 허용하지 않으면 확인을 제거하고 '.'이후에 둘 이상의 확인을 제거 할 수 있습니다 '.'. '-'TextBox에서 음수 값을 허용해야하는지 여부를 확인할 수도 있습니다 .

사용자를 자릿수로 제한하려면 다음을 사용하십시오. textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits


답변

한 줄로 작업하는 것이 항상 더 재미있어서 …

 private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
    }

참고 : 이렇게하면 사용자가이 텍스트 상자에 복사 / 붙여 넣기를 할 수 없습니다. 데이터를 안전하게 처리하는 안전한 방법은 아닙니다.


답변

컨텍스트와 .NET C # 앱을 작성하는 데 사용한 태그를 가정합니다. 이 경우 텍스트 변경 이벤트를 구독하고 각 키 입력을 확인할 수 있습니다.

private void textBox1_TextChanged(object sender, EventArgs e)
{
    if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
    {
        MessageBox.Show("Please enter only numbers.");
        textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
    }
}


답변

표준 TextBox에서 파생 된 간단한 독립 실행 형 Winforms 사용자 지정 컨트롤은 System.Int32 입력 만 허용합니다 (System.Int64 등의 다른 유형에 쉽게 적용 할 수 있음). 복사 / 붙여 넣기 작업과 음수를 지원합니다.

public class Int32TextBox : TextBox
{
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        base.OnKeyPress(e);

        NumberFormatInfo fi = CultureInfo.CurrentCulture.NumberFormat;

        string c = e.KeyChar.ToString();
        if (char.IsDigit(c, 0))
            return;

        if ((SelectionStart == 0) && (c.Equals(fi.NegativeSign)))
            return;

        // copy/paste
        if ((((int)e.KeyChar == 22) || ((int)e.KeyChar == 3))
            && ((ModifierKeys & Keys.Control) == Keys.Control))
            return;

        if (e.KeyChar == '\b')
            return;

        e.Handled = true;
    }

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        const int WM_PASTE = 0x0302;
        if (m.Msg == WM_PASTE)
        {
            string text = Clipboard.GetText();
            if (string.IsNullOrEmpty(text))
                return;

            if ((text.IndexOf('+') >= 0) && (SelectionStart != 0))
                return;

            int i;
            if (!int.TryParse(text, out i)) // change this for other integer types
                return;

            if ((i < 0) && (SelectionStart != 0))
                return;
        }
        base.WndProc(ref m);
    }

2017 업데이트 : 첫 번째 답변에는 몇 가지 문제가 있습니다.

  • 주어진 유형의 정수보다 긴 것을 입력 할 수 있습니다 (예 : 2147483648이 Int32.MaxValue보다 큼).
  • 더 일반적으로, 입력 된 결과 에 대한 실제 검증은 없습니다 .
  • int32 만 처리하므로 각 유형 (Int64 등)에 대해 특정 TextBox 파생 컨트롤을 작성해야합니다.

그래서 복사 / 붙여 넣기, + 및-기호 등을 계속 지원하는 더 일반적인 다른 버전을 생각해 냈습니다.

public class ValidatingTextBox : TextBox
{
    private string _validText;
    private int _selectionStart;
    private int _selectionEnd;
    private bool _dontProcessMessages;

    public event EventHandler<TextValidatingEventArgs> TextValidating;

    protected virtual void OnTextValidating(object sender, TextValidatingEventArgs e) => TextValidating?.Invoke(sender, e);

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (_dontProcessMessages)
            return;

        const int WM_KEYDOWN = 0x100;
        const int WM_ENTERIDLE = 0x121;
        const int VK_DELETE = 0x2e;

        bool delete = m.Msg == WM_KEYDOWN && (int)m.WParam == VK_DELETE;
        if ((m.Msg == WM_KEYDOWN && !delete) || m.Msg == WM_ENTERIDLE)
        {
            DontProcessMessage(() =>
            {
                _validText = Text;
                _selectionStart = SelectionStart;
                _selectionEnd = SelectionLength;
            });
        }

        const int WM_CHAR = 0x102;
        const int WM_PASTE = 0x302;
        if (m.Msg == WM_CHAR || m.Msg == WM_PASTE || delete)
        {
            string newText = null;
            DontProcessMessage(() =>
            {
                newText = Text;
            });

            var e = new TextValidatingEventArgs(newText);
            OnTextValidating(this, e);
            if (e.Cancel)
            {
                DontProcessMessage(() =>
                {
                    Text = _validText;
                    SelectionStart = _selectionStart;
                    SelectionLength = _selectionEnd;
                });
            }
        }
    }

    private void DontProcessMessage(Action action)
    {
        _dontProcessMessages = true;
        try
        {
            action();
        }
        finally
        {
            _dontProcessMessages = false;
        }
    }
}

public class TextValidatingEventArgs : CancelEventArgs
{
    public TextValidatingEventArgs(string newText) => NewText = newText;
    public string NewText { get; }
}

Int32의 경우 다음과 같이 파생시킬 수 있습니다.

public class Int32TextBox : ValidatingTextBox
{
    protected override void OnTextValidating(object sender, TextValidatingEventArgs e)
    {
        e.Cancel = !int.TryParse(e.NewText, out int i);
    }
}

또는 파생없이 다음과 같이 새로운 TextValidating 이벤트를 사용하십시오.

var vtb = new ValidatingTextBox();
...
vtb.TextValidating += (sender, e) => e.Cancel = !int.TryParse(e.NewText, out int i);

그러나 좋은 점은 모든 문자열 및 모든 유효성 검사 루틴에서 작동한다는 것입니다.


답변

바로 Validated / Validating 이벤트가 설계된 것입니다.

다음 주제에 대한 MSDN 기사입니다. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

TL; DR 버전 : Validating 이벤트에서 .Text 속성을 확인 e.Cancel=True하고 데이터가 유효하지 않을 때 설정 하십시오.

e.Cancel = True를 설정하면 사용자는 필드를 떠날 수 없지만 문제가있는 피드백을 제공해야합니다. 상자의 배경색을 밝은 빨간색으로 변경하여 문제를 나타냅니다. SystemColors.WindowValidating이 좋은 값으로 호출 될 때 다시 설정하십시오 .


답변

MaskedTextBox 사용해보십시오 . 간단한 마스크 형식을 사용하므로 입력을 숫자 나 날짜 등으로 제한 할 수 있습니다.


답변

당신은 TextChanged이벤트를 사용할 수 있습니다

private void textBox_BiggerThan_TextChanged(object sender, EventArgs e)
{
    long a;
    if (! long.TryParse(textBox_BiggerThan.Text, out a))
    {
        // If not int clear textbox text or Undo() last operation
        textBox_LessThan.Clear();
    }
}