Bagaimana cara membuat kotak teks yang hanya menerima angka?

583

Saya memiliki aplikasi bentuk windows dengan kontrol kotak teks yang saya ingin hanya menerima nilai integer. Di masa lalu saya telah melakukan validasi semacam ini dengan membebani acara KeyPress dan hanya menghapus karakter yang tidak sesuai dengan spesifikasi. Saya telah melihat kontrol MaskedTextBox tetapi saya ingin solusi yang lebih umum yang dapat bekerja dengan mungkin ekspresi reguler, atau bergantung pada nilai-nilai kontrol lain.

Idealnya ini akan berperilaku sedemikian sehingga menekan karakter non numerik akan menghasilkan hasil atau segera memberikan umpan balik kepada pengguna tentang karakter yang tidak valid.

Mykroft
sumber
11
angka atau digit? perbedaan besar: bahkan bilangan bulat dapat menjadi negatif
Joel Coehoorn
8
Pertanyaan itu dimaksudkan untuk angka termasuk seluruh rangkaian angka rasional.
Mykroft

Jawaban:

797

Dua pilihan:

  1. Gunakan NumericUpDownsaja. NumericUpDown melakukan penyaringan untuk Anda, yang bagus. Tentu saja itu juga memberi pengguna Anda kemampuan untuk menekan panah naik dan turun pada keyboard untuk menambah dan mengurangi nilai saat ini.

  2. Tangani acara keyboard yang sesuai untuk mencegah apa pun selain input numerik. Saya sudah sukses dengan dua penangan acara ini di TextBox standar:

    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;
        }
    }
    

Anda dapat menghapus cek untuk '.'(dan cek berikutnya untuk lebih dari satu '.') jika TextBox Anda tidak boleh mengizinkan tempat desimal. Anda juga bisa menambahkan tanda centang untuk '-'apakah TextBox Anda harus mengizinkan nilai negatif.

Jika Anda ingin membatasi pengguna untuk jumlah digit, gunakan: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits

Matt Hamilton
sumber
5
Satu-satunya kelemahan dengan NumericUpDown adalah tidak memberikan umpan balik ketika Anda memasukkan nilai di luar nilai maksimum atau minimum yang diizinkan - itu hanya mengubah apa yang Anda ketikkan. TextBox setidaknya dapat mengizinkan nilai yang tidak valid sehingga Anda dapat memperingatkan pengguna ketika mereka mengirimkan formulir.
Matt Hamilton
7
Itu benar - pengguna selalu dapat menempelkan beberapa karakter non-numerik. Anda akan berharap bahwa validasi formulir akan menangkap itu, karena pada titik tertentu Anda akan ingin melakukan Int32.TryParse atau sesuatu.
Matt Hamilton
52
Anda perlu upaya tambahan untuk mengglobalisasi ini dengan mengganti cek untuk '.' dengan cek di CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
Jeff Yates
6
@ HamishGrubijan, IsControl tidak ada hubungannya dengan kunci Kontrol; ia mengembalikan apakah char adalah char control atau tidak. Dengan mengizinkan kontrol chars, Anda tidak merusak hal-hal seperti backspace, delete atau tombol panah
Thomas Levesque
13
Omong-omong, ini masih menerima input ctrl + v ilegal; bug yang bahkan ada di kontrol NumericUpDown resmi.
Nyerguds
149

Dan hanya karena itu selalu lebih menyenangkan untuk melakukan hal-hal dalam satu baris ...

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

CATATAN: Ini TIDAK mencegah pengguna dari Copy / Paste ke dalam kotak teks ini. Ini bukan cara aman yang gagal untuk membersihkan data Anda.

BFree
sumber
ini bukan solusi umum karena hanya berfungsi untuk perantara. Saya harus mengimplementasikan hal tersebut baru-baru ini dan saya berakhir dengan mencoba-parsing string yang dihasilkan ke nomor dan memungkinkan input hanya jika parsing berhasil
grzegorz_p
1
Ini mungkin tidak berfungsi ketika beberapa metode menangani KeyPressacara dari kotak teks yang sama. Satu acara mungkin disetel e.Handledke true, lalu yang lain dapat mengaturnya kembali ke false. Secara umum, lebih baik digunakanif (...) e.Handled = true;
Nathaniel Jones
2
Anda dapat menonaktifkan properti ShortcutsEnabled untuk mencegah copy paste dengan keyboard atau menu
Ahmad
3
HA HA! Iya! Satu garis!
Jamie L.
3
Eh. Suatu TextChangedperistiwa yang mengatasinya dengan sebuah regex dapat memperbaiki copy-paste;)
Nyerguds
51

Saya mengasumsikan dari konteks dan tag yang Anda gunakan saat Anda sedang menulis aplikasi .NET C #. Dalam hal ini, Anda dapat berlangganan acara yang diubah teks, dan memvalidasi setiap stroke kunci.

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);
    }
}
Anthony D
sumber
22
Bukankah itu akan memberikan efek yang sangat aneh jika Anda mengetik di tengah angka?
Colin Pickard
5
dan juga harus:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
Pieniadz
3
bagaimana jika karakter pertama itu sendiri bukan angka ... tidak akan mengurangi 1 dalam kasus itu membuat kesalahan ....
manu_dilip_shah
6
Juga, menggunakan TextChanged bukan KeyPress menciptakan sedikit rekursi di mana kode akan melompat ke acara TextChanged kedua setelah metode Hapus.
WEFX
2
Anda mengganti parameter input dan pola untuk fungsi IsMatch Anda. Masukan harus terlebih dahulu, lalu pola. msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx
Mibou
36

Berikut ini adalah kontrol kustom Winforms mandiri yang sederhana, berasal dari TextBox standar, yang hanya memungkinkan input System.Int32 (bisa dengan mudah disesuaikan untuk jenis lain seperti System.Int64, dll.). Ini mendukung operasi salin / tempel dan angka negatif:

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);
    }

Pembaruan 2017 : Jawaban pertama saya memiliki beberapa masalah:

  • Anda dapat mengetik sesuatu yang lebih panjang dari bilangan bulat dari jenis yang diberikan (misalnya 2147483648 lebih besar dari Int32.MaxValue);
  • lebih umum, tidak ada validasi nyata dari hasil dari apa yang telah diketik;
  • hanya menangani int32, Anda harus menulis kontrol turunan TextBox khusus untuk setiap jenis (Int64, dll.)

Jadi saya datang dengan versi lain yang lebih umum, yang masih mendukung copy / paste, tanda +, dll.

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; }
}

Untuk Int32, Anda dapat menurunkannya, seperti ini:

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

atau tanpa derivasi, gunakan acara TextValidating baru seperti ini:

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

tapi apa yang baik itu berfungsi dengan string apa pun, dan rutin validasi apa pun.

Simon Mourier
sumber
Ini bagus, bagus dan sederhana, mudah digunakan, dan berkaitan dengan upaya input yang tidak biasa. Terima kasih!
WiredEarp
1
Catatan pada versi 2017, ketika ada satu nilai misalnya 1 dan Anda menekan backspace itu diabaikan sementara jika Anda telah mengatakan 120 dan tekan backspace tiga kali kita pergi dengan 1.
Karen Payne
1
ValidatingTextbox Anda sejauh ini merupakan implementasi terbaik yang pernah saya lihat untuk sementara waktu. Sederhana dan efektif. Terima kasih!
Samuel
19

Inilah yang dirancang untuk acara yang Divalidasi / Validasi.

Inilah artikel MSDN tentang topik ini: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

Versi TL; DR: periksa properti .Text di acara Validasi dan atur e.Cancel=Truesaat data tidak valid.

Ketika Anda mengatur e.Cancel = Benar, pengguna tidak dapat meninggalkan bidang, tetapi Anda harus memberi mereka semacam umpan balik bahwa ada sesuatu yang salah. Saya mengubah warna latar belakang kotak menjadi merah terang untuk menunjukkan masalah. Pastikan untuk mengaturnya kembali SystemColors.Windowsaat Validasi dipanggil dengan nilai yang baik.

TomXP411
sumber
1
+1 untuk menyebutkan pendekatan yang sangat idiom-API. Saya relatif baru untuk Windows Forms, dan itu cukup rimba fungsionalitas & dokumen MSDN, jadi juga terima kasih atas pointer dokumen khusus untuk Validating. <nitpick>OP menyebutkan bahwa penolakan langsung / mengindikasikan karakter yang tidak valid adalah ideal, tetapi Validatingtampaknya mengharuskan fokus dipindahkan ke bentuk / kontrol lain sebelum diberlakukan. </nitpick>Namun, ini adalah pendekatan yang bagus dan selalu layak dipertimbangkan dalam kasus yang lebih umum.
William
13

Coba MaskedTextBox . Dibutuhkan format mask sederhana sehingga Anda dapat membatasi input ke angka atau tanggal atau apa pun.

Andrew Kennan
sumber
2
Saya secara khusus tidak ingin menggunakan MaskedTextBox. Format yang dibolehkan bisa sangat membatasi. Mereka bekerja untuk kasus ini tetapi saya ingin melakukan sesuatu yang lebih umum.
Mykroft
12

Anda bisa menggunakan TextChangedacara tersebut

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();
    }
}
Davit Tvildiani
sumber
Sepertinya itu akan berfungsi dengan baik jika Anda digunakan Undo(), tetapi menghasilkan StackOverflowException.
Drew Chapin
Sepertinya kelayakan TextChanged adalah bagian dari rutin yang ingin Anda batalkan (). Saya memiliki variabel untuk seluruh jendela dan saya menggunakan public int txtBoxValue, dan jika tryParse tidak berfungsi, saya mengembalikan teks dalam txtBox olehtxtBox.Text = txtBoxValue.ToString();
L. Zeda
8

Ini mungkin bermanfaat. Ini memungkinkan nilai numerik "nyata", termasuk titik desimal yang tepat dan tanda plus atau minus sebelumnya. Sebut dari dalam acara KeyPress terkait.

       private bool IsOKForDecimalTextBox(char theCharacter, TextBox theTextBox)
    {
        // Only allow control characters, digits, plus and minus signs.
        // Only allow ONE plus sign.
        // Only allow ONE minus sign.
        // Only allow the plus or minus sign as the FIRST character.
        // Only allow ONE decimal point.
        // Do NOT allow decimal point or digits BEFORE any plus or minus sign.

        if (
            !char.IsControl(theCharacter)
            && !char.IsDigit(theCharacter)
            && (theCharacter != '.')
            && (theCharacter != '-')
            && (theCharacter != '+')
        )
        {
            // Then it is NOT a character we want allowed in the text box.
            return false;
        }



        // Only allow one decimal point.
        if (theCharacter == '.'
            && theTextBox.Text.IndexOf('.') > -1)
        {
            // Then there is already a decimal point in the text box.
            return false;
        }

        // Only allow one minus sign.
        if (theCharacter == '-'
            && theTextBox.Text.IndexOf('-') > -1)
        {
            // Then there is already a minus sign in the text box.
            return false;
        }

        // Only allow one plus sign.
        if (theCharacter == '+'
            && theTextBox.Text.IndexOf('+') > -1)
        {
            // Then there is already a plus sign in the text box.
            return false;
        }

        // Only allow one plus sign OR minus sign, but not both.
        if (
            (
                (theCharacter == '-')
                || (theCharacter == '+')
            )
            && 
            (
                (theTextBox.Text.IndexOf('-') > -1)
                ||
                (theTextBox.Text.IndexOf('+') > -1)
            )
            )
        {
            // Then the user is trying to enter a plus or minus sign and
            // there is ALREADY a plus or minus sign in the text box.
            return false;
        }

        // Only allow a minus or plus sign at the first character position.
        if (
            (
                (theCharacter == '-')
                || (theCharacter == '+')
            )
            && theTextBox.SelectionStart != 0
            )
        {
            // Then the user is trying to enter a minus or plus sign at some position 
            // OTHER than the first character position in the text box.
            return false;
        }

        // Only allow digits and decimal point AFTER any existing plus or minus sign
        if  (
                (
                    // Is digit or decimal point
                    char.IsDigit(theCharacter)
                    ||
                    (theCharacter == '.')
                )
                &&
                (
                    // A plus or minus sign EXISTS
                    (theTextBox.Text.IndexOf('-') > -1)
                    ||
                    (theTextBox.Text.IndexOf('+') > -1)
                )
                &&
                    // Attempting to put the character at the beginning of the field.
                    theTextBox.SelectionStart == 0
            )
        {
            // Then the user is trying to enter a digit or decimal point in front of a minus or plus sign.
            return false;
        }

        // Otherwise the character is perfectly fine for a decimal value and the character
        // may indeed be placed at the current insertion position.
        return true;
    }
Roger Garrett
sumber
6

Saya telah mengerjakan kumpulan komponen untuk melengkapi barang yang hilang di WinForms, ini dia: Advanced Forms

Khususnya ini adalah kelas untuk Regex TextBox

/// <summary>Represents a Windows text box control that only allows input that matches a regular expression.</summary>
public class RegexTextBox : TextBox
{
    [NonSerialized]
    string lastText;

    /// <summary>A regular expression governing the input allowed in this text field.</summary>
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual Regex Regex { get; set; }

    /// <summary>A regular expression governing the input allowed in this text field.</summary>
    [DefaultValue(null)]
    [Category("Behavior")]
    [Description("Sets the regular expression governing the input allowed for this control.")]
    public virtual string RegexString {
        get {
            return Regex == null ? string.Empty : Regex.ToString();
        }
        set {
            if (string.IsNullOrEmpty(value))
                Regex = null;
            else
                Regex = new Regex(value);
        }
    }

    protected override void OnTextChanged(EventArgs e) {
        if (Regex != null && !Regex.IsMatch(Text)) {
            int pos = SelectionStart - Text.Length + (lastText ?? string.Empty).Length;
            Text = lastText;
            SelectionStart = Math.Max(0, pos);
        }

        lastText = Text;

        base.OnTextChanged(e);
    }
}

Cukup menambahkan sesuatu seperti myNumbericTextBox.RegexString = "^(\\d+|)$";sudah cukup.

Fabio Iotti
sumber
5

Cukup gunakan NumericUpDownkontrol dan atur visibilitas tombol jelek ke bawah false.

numericUpDown1.Controls[0].Visible = false;

NumericUpDown sebenarnya adalah kumpulan kontrol yang berisi 'spin box' (tombol atas ke bawah), kotak teks dan beberapa kode untuk memvalidasi dan mengayunkan semuanya secara bersamaan.

Menandai:

YourNumericUpDown.Controls[0].visible = false 

akan menyembunyikan tombol sambil menjaga kode yang mendasarinya aktif.

Meskipun tidak menjadi solusi yang jelas itu sederhana dan efektif. .Controls[1]akan menyembunyikan bagian kotak teks jika Anda ingin melakukannya.

pengguna2163234
sumber
Jawaban yang diterima tidak mencakup informasi apa pun tentang cara menghapus tombol naik turun, cara melakukannya tidak jelas karena tidak ada antarmuka yang dapat dibaca manusia untuk mengaktifkan atau menonaktifkannya. NumericUpDown sebenarnya adalah kumpulan kontrol yang berisi kotak teks dan "spin box" (tombol atas ke bawah) dan beberapa validasi input penanganan kode.
user2163234
4

Saya telah membuat sesuatu untuk ini di CodePlex .

Ini bekerja dengan mencegat acara TextChanged. Jika hasilnya angka yang baik maka akan disimpan. Jika ada yang salah, nilai barang terakhir akan dikembalikan. Sumbernya agak terlalu besar untuk diterbitkan di sini, tetapi di sini ada tautan ke kelas yang menangani inti dari logika ini.

GvS
sumber
4

cukup gunakan kode ini di kotak teks:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

    if (!double.TryParse(textBox1.Text, out parsedValue))
    {
        textBox1.Text = "";
    }
}
saurabh27
sumber
4

Di halaman web kami dengan definisi kotak teks, kami dapat menambahkan onkeypressacara untuk hanya menerima angka. Itu tidak akan menampilkan pesan apa pun tetapi itu akan mencegah Anda dari input yang salah. Ini bekerja untuk saya, pengguna tidak bisa memasukkan apa pun kecuali nomor

<asp:TextBox runat="server" ID="txtFrom"
     onkeypress="if(isNaN(String.fromCharCode(event.keyCode))) return false;">
ssah
sumber
2

Anda bisa menggunakan acara TextChanged / Keypress, gunakan regex untuk memfilter angka dan mengambil tindakan.

Perpetualcoder
sumber
2

Saya akan menanganinya di acara KeyDown.

void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            char c = Convert.ToChar(e.PlatformKeyCode);
            if (!char.IsDigit(c))
            {
                e.Handled = true;
            }
        }
Shaz
sumber
2
Bagaimana dengan Tombol seperti "Backspace", "Hapus", "Panah-Kunci-Kiri", "Panah-Kunci-Kanan", Salin dan Tempel, Digit yang dimasukkan oleh Numpad (mereka diperjualbelikan sebagai digit!)
user799821
Tambahkan saja beberapa tes seperti ini: if (! Char.IsDigit (c) && c! = (Char) Keys.Back)
dnennis
2
private void txt3_KeyPress(object sender, KeyPressEventArgs e)
{
    for (int h = 58; h <= 127; h++)
    {
        if (e.KeyChar == h)             //58 to 127 is alphabets tat will be         blocked
        {
            e.Handled = true;
        }
    }
    for(int k=32;k<=47;k++)
    {
        if (e.KeyChar == k)              //32 to 47 are special characters tat will 
        {                                  be blocked
            e.Handled = true;
        }
    }
}

coba ini sangat sederhana

rithish
sumber
2

Lihatlah penanganan Input di WinForm

Saya telah memposting solusi saya yang menggunakan acara ProcessCmdKey dan OnKeyPress di kotak teks. Komentar menunjukkan kepada Anda cara menggunakan Regex untuk memverifikasi penekanan tombol dan memblokir / mengizinkan secara tepat.

benPearce
sumber
2

Hai, Anda dapat melakukan sesuatu seperti ini di ajang textbox yang telah diubah.

ini demo

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        string actualdata = string.Empty;
        char[] entereddata = textBox1.Text.ToCharArray();
        foreach (char aChar in entereddata.AsEnumerable())
        {
            if (Char.IsDigit(aChar))
            {
                actualdata = actualdata + aChar;
                // MessageBox.Show(aChar.ToString());
            }
            else
            {
                MessageBox.Show(aChar + " is not numeric");
                actualdata.Replace(aChar, ' ');
                actualdata.Trim();
            }
        }
        textBox1.Text = actualdata;
    }
Chandan Kumar
sumber
Terima kasih, ini sangat berguna.
Kiran RS
2

Sepertinya banyak dari jawaban saat ini untuk pertanyaan ini secara manual mem-parsing teks input. Jika Anda mencari tipe numerik bawaan tertentu (misalnya intatau double), mengapa tidak mendelegasikan pekerjaan ke TryParsemetode tipe itu saja ? Sebagai contoh:

public class IntTextBox : TextBox
{
    string PreviousText = "";
    int BackingResult;

    public IntTextBox()
    {
        TextChanged += IntTextBox_TextChanged;
    }

    public bool HasResult { get; private set; }

    public int Result
    {
        get
        {
            return HasResult ? BackingResult : default(int);
        }
    }

    void IntTextBox_TextChanged(object sender, EventArgs e)
    {
        HasResult = int.TryParse(Text, out BackingResult);

        if (HasResult || string.IsNullOrEmpty(Text))
        {
            // Commit
            PreviousText = Text;
        }
        else
        {
            // Revert
            var changeOffset = Text.Length - PreviousText.Length;
            var previousSelectionStart =
                Math.Max(0, SelectionStart - changeOffset);

            Text = PreviousText;
            SelectionStart = previousSelectionStart;
        }
    }
}

Jika Anda menginginkan sesuatu yang lebih umum tetapi masih kompatibel dengan Desainer Visual Studio:

public class ParsableTextBox : TextBox
{
    TryParser BackingTryParse;
    string PreviousText = "";
    object BackingResult;

    public ParsableTextBox()
        : this(null)
    {
    }

    public ParsableTextBox(TryParser tryParse)
    {
        TryParse = tryParse;

        TextChanged += ParsableTextBox_TextChanged;
    }

    public delegate bool TryParser(string text, out object result);

    public TryParser TryParse
    {
        set
        {
            Enabled = !(ReadOnly = value == null);

            BackingTryParse = value;
        }
    }

    public bool HasResult { get; private set; }

    public object Result
    {
        get
        {
            return GetResult<object>();
        }
    }

    public T GetResult<T>()
    {
        return HasResult ? (T)BackingResult : default(T);
    }

    void ParsableTextBox_TextChanged(object sender, EventArgs e)
    {
        if (BackingTryParse != null)
        {
            HasResult = BackingTryParse(Text, out BackingResult);
        }

        if (HasResult || string.IsNullOrEmpty(Text))
        {
            // Commit
            PreviousText = Text;
        }
        else
        {
            // Revert
            var changeOffset = Text.Length - PreviousText.Length;
            var previousSelectionStart =
                Math.Max(0, SelectionStart - changeOffset);

            Text = PreviousText;
            SelectionStart = previousSelectionStart;
        }
    }
}

Dan akhirnya, jika Anda menginginkan sesuatu yang sepenuhnya generik dan tidak peduli dengan dukungan Designer:

public class ParsableTextBox<T> : TextBox
{
    TryParser BackingTryParse;
    string PreviousText;
    T BackingResult;

    public ParsableTextBox()
        : this(null)
    {
    }

    public ParsableTextBox(TryParser tryParse)
    {
        TryParse = tryParse;

        TextChanged += ParsableTextBox_TextChanged;
    }

    public delegate bool TryParser(string text, out T result);

    public TryParser TryParse
    {
        set
        {
            Enabled = !(ReadOnly = value == null);

            BackingTryParse = value;
        }
    }

    public bool HasResult { get; private set; }

    public T Result
    {
        get
        {
            return HasResult ? BackingResult : default(T);
        }
    }

    void ParsableTextBox_TextChanged(object sender, EventArgs e)
    {
        if (BackingTryParse != null)
        {
            HasResult = BackingTryParse(Text, out BackingResult);
        }

        if (HasResult || string.IsNullOrEmpty(Text))
        {
            // Commit
            PreviousText = Text;
        }
        else
        {
            // Revert
            var changeOffset = Text.Length - PreviousText.Length;
            var previousSelectionStart =
                Math.Max(0, SelectionStart - changeOffset);

            Text = PreviousText;
            SelectionStart = previousSelectionStart;
        }
    }
}
William
sumber
2

Bilangan bulat dan pelampung perlu diterima, termasuk bilangan negatif.

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    // Text
    string text = ((Control) sender).Text;

    // Is Negative Number?
    if (e.KeyChar == '-' && text.Length == 0)
    {
        e.Handled = false;
        return;
    }

    // Is Float Number?
    if (e.KeyChar == '.' && text.Length > 0 && !text.Contains("."))
    {
        e.Handled = false;
        return;
    }

    // Is Digit?
    e.Handled = (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar));
}
nabeghe
sumber
2

Ini adalah pendekatan saya:

  1. menggunakan LINQ (mudah untuk memodifikasi filter)
  2. salin / tempel kode bukti
  3. menjaga posisi caret ketika Anda menekan karakter terlarang
  4. menerima nol yang tersisa
  5. dan angka ukuran apa saja

    private void numeroCuenta_TextChanged(object sender, EventArgs e)
    {
        string org = numeroCuenta.Text;
        string formated = string.Concat(org.Where(c => (c >= '0' && c <= '9')));
        if (formated != org)
        {
            int s = numeroCuenta.SelectionStart;
            if (s > 0 && formated.Length > s && org[s - 1] != formated[s - 1]) s--;
            numeroCuenta.Text = formated;
            numeroCuenta.SelectionStart = s;
        }
    }
Ing. Gerardo Sánchez
sumber
2

Menggunakan pendekatan yang dijelaskan dalam jawaban Fabio Iotti, saya telah menciptakan solusi yang lebih umum:

public abstract class ValidatedTextBox : TextBox {
    private string m_lastText = string.Empty;
    protected abstract bool IsValid(string text);
    protected sealed override void OnTextChanged(EventArgs e) {
        if (!IsValid(Text)) {
            var pos = SelectionStart - Text.Length + m_lastText.Length;
            Text = m_lastText;
            SelectionStart = Math.Max(0, pos);
        }
        m_lastText = Text;
        base.OnTextChanged(e);
    }
}

"ValidatedTextBox", yang berisi semua perilaku validasi nontrivial. Yang tersisa untuk dilakukan adalah mewarisi dari kelas ini dan mengganti metode "IsValid" dengan logika validasi apa pun yang diperlukan. Misalnya, menggunakan kelas ini, dimungkinkan untuk membuat "RegexedTextBox" yang hanya akan menerima string yang cocok dengan ekspresi reguler spesifik:

public abstract class RegexedTextBox : ValidatedTextBox {
    private readonly Regex m_regex;
    protected RegexedTextBox(string regExpString) {
        m_regex = new Regex(regExpString);
    }
    protected override bool IsValid(string text) {
        return m_regex.IsMatch(Text);
    }
}

Setelah itu, mewarisi dari kelas "RegexedTextBox", kita dapat dengan mudah membuat kontrol "PositiveNumberTextBox" dan "PositiveFloatingPointNumberTextBox":

public sealed class PositiveNumberTextBox : RegexedTextBox {
    public PositiveNumberTextBox() : base(@"^\d*$") { }
}

public sealed class PositiveFloatingPointNumberTextBox : RegexedTextBox {
    public PositiveFloatingPointNumberTextBox()
        : base(@"^(\d+\" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + @")?\d*$") { }
}
Beruang kutub
sumber
1

Maaf membangunkan orang mati, tetapi saya pikir seseorang mungkin menemukan ini berguna untuk referensi di masa depan.

Inilah cara saya menanganinya. Ini menangani angka floating point, tetapi dapat dengan mudah dimodifikasi untuk bilangan bulat.

Pada dasarnya Anda hanya dapat menekan 0 - 9 dan .

Anda hanya dapat memiliki satu 0 sebelum .

Semua karakter lain diabaikan dan posisi kursor dipertahankan.

    private bool _myTextBoxChanging = false;

    private void myTextBox_TextChanged(object sender, EventArgs e)
    {
        validateText(myTextBox);
    }

    private void validateText(TextBox box)
    {
        // stop multiple changes;
        if (_myTextBoxChanging)
            return;
        _myTextBoxChanging = true;

        string text = box.Text;
        if (text == "")
            return;
        string validText = "";
        bool hasPeriod = false;
        int pos = box.SelectionStart;
        for (int i = 0; i < text.Length; i++ )
        {
            bool badChar = false;
            char s = text[i];
            if (s == '.')
            {
                if (hasPeriod)
                    badChar = true;
                else
                    hasPeriod = true;
            }
            else if (s < '0' || s > '9')
                badChar = true;

            if (!badChar)
                validText += s;
            else
            {
                if (i <= pos)
                    pos--;
            }
        }

        // trim starting 00s
        while (validText.Length >= 2 && validText[0] == '0')
        {
            if (validText[1] != '.')
            {
                validText = validText.Substring(1);
                if (pos < 2)
                    pos--;
            }
            else
                break;
        }

        if (pos > validText.Length)
            pos = validText.Length;
        box.Text = validText;
        box.SelectionStart = pos;
        _myTextBoxChanging = false;
    }

Ini adalah versi int yang cepat dimodifikasi:

    private void validateText(TextBox box)
    {
        // stop multiple changes;
        if (_myTextBoxChanging)
            return;
        _myTextBoxChanging = true;

        string text = box.Text;
        if (text == "")
            return;
        string validText = "";
        int pos = box.SelectionStart;
        for (int i = 0; i < text.Length; i++ )
        {
            char s = text[i];
            if (s < '0' || s > '9')
            {
                if (i <= pos)
                    pos--;
            }
            else
                validText += s;
        }

        // trim starting 00s 
        while (validText.Length >= 2 && validText.StartsWith("00")) 
        { 
            validText = validText.Substring(1); 
            if (pos < 2) 
                pos--; 
        } 

        if (pos > validText.Length)
            pos = validText.Length;
        box.Text = validText;
        box.SelectionStart = pos;
        _myTextBoxChanging = false;
    }
yardape
sumber
2
Solusi ini adalah menciptakan kembali roda dengan peringatan. Lokalisasi misalnya.
Julien Guertault
1

Yang ini bekerja dengan salin dan tempel, seret dan lepas, kunci ke bawah, mencegah overflow dan cukup sederhana

public partial class IntegerBox : TextBox 
{
    public IntegerBox()
    {
        InitializeComponent();
        this.Text = 0.ToString();
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        base.OnPaint(pe);
    }

    private String originalValue = 0.ToString();

    private void Integerbox_KeyPress(object sender, KeyPressEventArgs e)
    {
        originalValue = this.Text;
    }

    private void Integerbox_TextChanged(object sender, EventArgs e)
    {
        try
        {
            if(String.IsNullOrWhiteSpace(this.Text))
            {
                this.Text = 0.ToString();
            }
            this.Text = Convert.ToInt64(this.Text.Trim()).ToString();
        }
        catch (System.OverflowException)
        {
            MessageBox.Show("Value entered is to large max value: " + Int64.MaxValue.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            this.Text = originalValue;
        }
        catch (System.FormatException)
        {                
            this.Text = originalValue;
        }
        catch (System.Exception ex)
        {
            this.Text = originalValue;
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK , MessageBoxIcon.Error);
        }
    }       
}
pengguna1626874
sumber
1

Jangan lupa bahwa pengguna dapat menempelkan teks yang tidak valid di a TextBox.

Jika Anda ingin membatasi itu, ikuti kode di bawah ini:

private void ultraTextEditor1_TextChanged(object sender, EventArgs e)
{
    string append="";
    foreach (char c in ultraTextEditor1.Text)
    {
        if ((!Char.IsNumber(c)) && (c != Convert.ToChar(Keys.Back)))
        {

        }
        else
        {
            append += c;
        }
    }

    ultraTextEditor1.Text = append;
}   
Divya
sumber
1

Saya juga mencari cara terbaik untuk memeriksa hanya angka dalam kotak teks dan masalah dengan penekanan tombol adalah tidak mendukung copy paste dengan klik kanan atau clipboard sehingga muncul dengan kode ini yang memvalidasi ketika kursor meninggalkan bidang teks dan juga memeriksa untuk bidang kosong. (versi yang diadaptasi dari newguy)

private void txtFirstValue_MouseLeave(object sender, EventArgs e)
{
    int num;
    bool isNum = int.TryParse(txtFirstValue.Text.Trim(), out num);

    if (!isNum && txtFirstValue.Text != String.Empty)
    {
        MessageBox.Show("The First Value You Entered Is Not a Number, Please Try Again", "Invalid Value Detected", MessageBoxButtons.OK, MessageBoxIcon.Error);
        txtFirstValue.Clear();
    }
}
Alston Antony
sumber
MouseLeave sepertinya pilihan yang sangat buruk untuk digunakan suatu acara.
LarsTech
@ LarsTech apa yang saya pikir telah berubah teks bahkan dapat menyebabkan pesan kesalahan sebelum bahkan jika pengguna menyadari kesalahan dan mencoba untuk memperbaikinya jadi saya pikir saya akan bekerja lebih baik. Menurut Anda, apa acara terbaik untuk kasus ini?
Alston Antony
@AlstonAntony komentar terlambat, saya tahu. Tetapi acara klik sederhana yang diaktifkan di klik kanan akan cukup bukan?
Takarii
0
int Number;
bool isNumber;
isNumber = int32.TryPase(textbox1.text, out Number);

if (!isNumber)
{ 
    (code if not an integer);
}
else
{
    (code if an integer);
}
orang baru
sumber
0

3 solusi

1)

//Add to the textbox's KeyPress event
//using Regex for number only textBox

private void txtBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(), "\\d+"))
e.Handled = true;
}

2) solusi lain dari msdn

// Boolean flag used to determine when a character other than a number is entered.
private bool nonNumberEntered = false;
// Handle the KeyDown event to determine the type of character entered into the     control.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
// Initialize the flag to false.
nonNumberEntered = false;
// Determine whether the keystroke is a number from the top of the keyboard.
if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
{
    // Determine whether the keystroke is a number from the keypad.
    if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
    {
        // Determine whether the keystroke is a backspace.
        if (e.KeyCode != Keys.Back)
        {
            // A non-numerical keystroke was pressed.
            // Set the flag to true and evaluate in KeyPress event.
            nonNumberEntered = true;
        }
    }
}

}

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (nonNumberEntered == true)
    {
       MessageBox.Show("Please enter number only..."); 
       e.Handled = true;
    }
}

sumber http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress(v=VS.90).aspx

3) menggunakan MaskedTextBox: http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx

gadis sederhana dan imut
sumber
0

Di klik tombol Anda dapat memeriksa teks kotak teks dengan untuk loop:

char[] c = txtGetCustomerId.Text.ToCharArray();
bool IsDigi = true;

for (int i = 0; i < c.Length; i++)
     {
       if (c[i] < '0' || c[i] > '9')
      { IsDigi = false; }
     }
 if (IsDigi)
    { 
     // do something
    }
Shaahin
sumber
0

Jawaban yang lebih sederhana:

_textBox.TextChanged += delegate(System.Object o, System.EventArgs e)
{
    TextBox _tbox = o as TextBox;
    _tbox.Text = new string(_tbox.Text.Where(c => (char.IsDigit(c)) || (c == '.')).ToArray());
};
micahhoover
sumber