Bagaimana cara saya mendapatkan TextBox untuk hanya menerima input numerik di WPF?

335

Saya ingin menerima angka dan titik desimal, tetapi tidak ada tanda.

Saya telah melihat sampel menggunakan kontrol NumericUpDown untuk Windows Forms, dan sampel kontrol kustom NumericUpDown ini dari Microsoft . Tapi sejauh ini sepertinya NumericUpDown (didukung oleh WPF atau tidak) tidak akan menyediakan fungsionalitas yang saya inginkan. Cara aplikasi saya dirancang, tidak ada orang waras yang mau mengacaukan panah. Mereka tidak masuk akal secara praktis, dalam konteks aplikasi saya.

Jadi saya sedang mencari cara sederhana untuk membuat WPF TextBox standar hanya menerima karakter yang saya inginkan. Apakah ini mungkin? Apakah ini praktis?

Giffyguy
sumber

Jawaban:

418

Tambahkan acara input teks pratinjau. Seperti: <TextBox PreviewTextInput="PreviewTextInput" />.

Kemudian di dalam yang mengatur e.Handledjika teks tidak diizinkan.e.Handled = !IsTextAllowed(e.Text);

Saya menggunakan regex sederhana dalam IsTextAllowedmetode untuk melihat apakah saya harus mengizinkan apa yang mereka ketikkan. Dalam kasus saya, saya hanya ingin memperbolehkan angka, titik, dan garis putus-putus.

private static readonly Regex _regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
private static bool IsTextAllowed(string text)
{
    return !_regex.IsMatch(text);
}

Jika Anda ingin mencegah menempelnya data yang tidak benar, kaitkan DataObject.Pastingacara DataObject.Pasting="TextBoxPasting"seperti yang ditunjukkan di sini (cuplikan kode):

// Use the DataObject.Pasting Handler 
private void TextBoxPasting(object sender, DataObjectPastingEventArgs e)
{
    if (e.DataObject.GetDataPresent(typeof(String)))
    {
        String text = (String)e.DataObject.GetData(typeof(String));
        if (!IsTextAllowed(text))
        {
            e.CancelCommand();
        }
    }
    else
    {
        e.CancelCommand();
    }
}
sinar
sumber
5
Regex Anda tidak mengizinkan notasi ilmiah (1e5) jika itu penting.
Ron Warholic
14
Perhatikan bahwa jawaban ini hanya memeriksa apa yang Anda ketikkan, sehingga Anda bisa memasukkan 3-.3
David Sykes
153
Inti dari jawabannya bukan untuk menentukan Regex yang sempurna, itu untuk menunjukkan bagaimana menggunakan WPF untuk memfilter tipe orang apa.
Ray
27
[Spasi] tidak memicu acara PreviewTextInput.
peterG
5
Sesuatu seperti double.TryParse()mungkin akan diimplementasikan dengan jumlah baris yang sama dan lebih fleksibel.
Thomas Weller
190

Pengatur kejadian sedang mempratinjau input teks. Di sini ekspresi reguler hanya cocok dengan input teks jika bukan angka, dan kemudian tidak dibuat untuk masuk ke kotak teks.

Jika Anda hanya menginginkan huruf, maka ganti ekspresi reguler dengan [^a-zA-Z].

XAML

<TextBox Name="NumberTextBox" PreviewTextInput="NumberValidationTextBox"/>

FILE XAML.CS

using System.Text.RegularExpressions;
private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
{
    Regex regex = new Regex("[^0-9]+");
    e.Handled = regex.IsMatch(e.Text);
}
Kishor
sumber
1
Penangan acara adalah input teks pratinjau. Di sini persamaan reguler hanya cocok dengan input teks jika bukan angka, maka itu tidak dibuat untuk masuk ke kotak teks. Jika Anda hanya menginginkan huruf, gantilah ekspresi reguler sebagai [^ a-zA-Z].
Kishor
Bagaimana dengan angka, desimal, dan operator?
Jason Ebersey
Tolong beri tahu saya cara menggunakannya ketika mendeklarasikan di beberapa kelas STATIC lainnya dan mendaftar ke kotak teks?
SHEKHAR SHETE
3
Saya suka yang ini lebih dari jawaban yang sebenarnya, pendek dan sederhana. Jawaban aktual membutuhkan dua metode untuk mendapatkan hasil yang sama.
Sliver
1
@Jagd Jawaban yang disarankan adalah pemisahan masalah yang lebih baik. Namun Anda juga dapat mengatur banyak kotak teks pada validasi ini. cukup tambahkan PreviewTextInput = "NumberValidationTextBox". (seperti jawaban yang lain!)
Sliver
84

Saya menggunakan beberapa dari apa yang sudah ada di sini dan menempatkan twist saya sendiri di atasnya menggunakan perilaku jadi saya tidak perlu menyebarkan kode ini sepanjang satu ton Tampilan ...

public class AllowableCharactersTextBoxBehavior : Behavior<TextBox>
{
    public static readonly DependencyProperty RegularExpressionProperty =
         DependencyProperty.Register("RegularExpression", typeof(string), typeof(AllowableCharactersTextBoxBehavior),
         new FrameworkPropertyMetadata(".*"));
    public string RegularExpression
    {
        get
        {
            return (string)base.GetValue(RegularExpressionProperty);
        }
        set
        {
            base.SetValue(RegularExpressionProperty, value);
        }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof(int), typeof(AllowableCharactersTextBoxBehavior),
        new FrameworkPropertyMetadata(int.MinValue));
    public int MaxLength
    {
        get
        {
            return (int)base.GetValue(MaxLengthProperty);
        }
        set
        {
            base.SetValue(MaxLengthProperty, value);
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewTextInput += OnPreviewTextInput;
        DataObject.AddPastingHandler(AssociatedObject, OnPaste);
    }

    private void OnPaste(object sender, DataObjectPastingEventArgs e)
    {
        if (e.DataObject.GetDataPresent(DataFormats.Text))
        {
            string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

            if (!IsValid(text, true))
            {
                e.CancelCommand();
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsValid(e.Text, false);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewTextInput -= OnPreviewTextInput;
        DataObject.RemovePastingHandler(AssociatedObject, OnPaste);
    }

    private bool IsValid(string newText, bool paste)
    {
        return !ExceedsMaxLength(newText, paste) && Regex.IsMatch(newText, RegularExpression);
    }

    private bool ExceedsMaxLength(string newText, bool paste)
    {
        if (MaxLength == 0) return false;

        return LengthOfModifiedText(newText, paste) > MaxLength;
    }

    private int LengthOfModifiedText(string newText, bool paste)
    {
        var countOfSelectedChars = this.AssociatedObject.SelectedText.Length;
        var caretIndex = this.AssociatedObject.CaretIndex;
        string text = this.AssociatedObject.Text;

        if (countOfSelectedChars > 0 || paste)
        {
            text = text.Remove(caretIndex, countOfSelectedChars);
            return text.Length + newText.Length;
        }
        else
        {
            var insert = Keyboard.IsKeyToggled(Key.Insert);

            return insert && caretIndex < text.Length ? text.Length : text.Length + newText.Length;
        }
    }
}

Berikut ini adalah kode tampilan yang relevan:

<TextBox MaxLength="50" TextWrapping="Wrap" MaxWidth="150" Margin="4"
 Text="{Binding Path=FileNameToPublish}" >
     <interactivity:Interaction.Behaviors>
         <v:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9.\-]+$" MaxLength="50" />
     </interactivity:Interaction.Behaviors>
</TextBox>
Wil P
sumber
1
Terinspirasi oleh solusi yang luar biasa ini, saya menerapkan beberapa perbaikan. Silakan periksa di bawah di utas.
Alex Klaus
2
Hai. Saya tahu ini agak terlambat tapi saya mencoba menerapkan ini tetapi saya terus mendapatkan kesalahan. Saya kira saya kehilangan beberapa referensi. Apakah ada yang dimaksudkan untuk diketik selain dari default setelah Anda membuat kelas?
Tawarkan
1
@ Penawaran Ya, pastikan untuk menyertakan xmlns: interaktivitas = " schemas.microsoft.com/expression/2010/interactivity " di bagian atas jendela xaml Anda.
WiteCastle
Ekspresi sekarang sudah usang. Meskipun pendekatan ini bersih, namun menggunakan kode yang tidak lagi dipertahankan.
Robert Baker
1
Jadi jika Anda mengedit fungsi IsValid untuk kembali! ExceedMaxLength (newText, paste) && Regex.IsMatch (String.Compat (this.AssociatedObject.Text, newText), RegularExpression); maka ini akan mengevaluasi seluruh string. Btw - Suka opsi ini dengan perilakunya !!
Rogala
59

Ini adalah solusi yang lebih baik dari jawaban WilP . Peningkatan saya adalah:

  • Perilaku yang ditingkatkan pada tombol Del dan Backspace
  • Menambahkan EmptyValueproperti, jika string kosong tidak pantas
  • Memperbaiki beberapa kesalahan ketik kecil
/// <summary>
///     Regular expression for Textbox with properties: 
///         <see cref="RegularExpression"/>, 
///         <see cref="MaxLength"/>,
///         <see cref="EmptyValue"/>.
/// </summary>
public class TextBoxInputRegExBehaviour : Behavior<TextBox>
{
    #region DependencyProperties
    public static readonly DependencyProperty RegularExpressionProperty =
        DependencyProperty.Register("RegularExpression", typeof(string), typeof(TextBoxInputRegExBehaviour), new FrameworkPropertyMetadata(".*"));

    public string RegularExpression
    {
        get { return (string)GetValue(RegularExpressionProperty); }
        set { SetValue(RegularExpressionProperty, value); }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof(int), typeof(TextBoxInputRegExBehaviour),
                                        new FrameworkPropertyMetadata(int.MinValue));

    public int MaxLength
    {
        get { return (int)GetValue(MaxLengthProperty); }
        set { SetValue(MaxLengthProperty, value); }
    }

    public static readonly DependencyProperty EmptyValueProperty =
        DependencyProperty.Register("EmptyValue", typeof(string), typeof(TextBoxInputRegExBehaviour), null);

    public string EmptyValue
    {
        get { return (string)GetValue(EmptyValueProperty); }
        set { SetValue(EmptyValueProperty, value); }
    }
    #endregion

    /// <summary>
    ///     Attach our behaviour. Add event handlers
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
        AssociatedObject.PreviewKeyDown += PreviewKeyDownHandler;
        DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
    }

    /// <summary>
    ///     Deattach our behaviour. remove event handlers
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
        AssociatedObject.PreviewKeyDown -= PreviewKeyDownHandler;
        DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
    }

    #region Event handlers [PRIVATE] --------------------------------------

    void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
    {
        string text;
        if (this.AssociatedObject.Text.Length < this.AssociatedObject.CaretIndex)
            text = this.AssociatedObject.Text;
        else
        {
            //  Remaining text after removing selected text.
            string remainingTextAfterRemoveSelection;

            text = TreatSelectedText(out remainingTextAfterRemoveSelection)
                ? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
                : AssociatedObject.Text.Insert(this.AssociatedObject.CaretIndex, e.Text);
        }

        e.Handled = !ValidateText(text);
    }

    /// <summary>
    ///     PreviewKeyDown event handler
    /// </summary>
    void PreviewKeyDownHandler(object sender, KeyEventArgs e)
    {
        if (string.IsNullOrEmpty(this.EmptyValue))
            return;

        string text = null;

        // Handle the Backspace key
        if (e.Key == Key.Back)
        {
            if (!this.TreatSelectedText(out text))
            {
                if (AssociatedObject.SelectionStart > 0)
                    text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart - 1, 1);
            }
        }
        // Handle the Delete key
        else if (e.Key == Key.Delete)
        {
            // If text was selected, delete it
            if (!this.TreatSelectedText(out text) && this.AssociatedObject.Text.Length > AssociatedObject.SelectionStart)
            {
                // Otherwise delete next symbol
                text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, 1);
            }
        }

        if (text == string.Empty)
        {
            this.AssociatedObject.Text = this.EmptyValue;
            if (e.Key == Key.Back)
                AssociatedObject.SelectionStart++;
            e.Handled = true;
        }
    }

    private void PastingHandler(object sender, DataObjectPastingEventArgs e)
    {
        if (e.DataObject.GetDataPresent(DataFormats.Text))
        {
            string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

            if (!ValidateText(text))
                e.CancelCommand();
        }
        else
            e.CancelCommand();
    }
    #endregion Event handlers [PRIVATE] -----------------------------------

    #region Auxiliary methods [PRIVATE] -----------------------------------

    /// <summary>
    ///     Validate certain text by our regular expression and text length conditions
    /// </summary>
    /// <param name="text"> Text for validation </param>
    /// <returns> True - valid, False - invalid </returns>
    private bool ValidateText(string text)
    {
        return (new Regex(this.RegularExpression, RegexOptions.IgnoreCase)).IsMatch(text) && (MaxLength == int.MinValue || text.Length <= MaxLength);
    }

    /// <summary>
    ///     Handle text selection
    /// </summary>
    /// <returns>true if the character was successfully removed; otherwise, false. </returns>
    private bool TreatSelectedText(out string text)
    {
        text = null;
        if (AssociatedObject.SelectionLength <= 0) 
            return false;

        var length = this.AssociatedObject.Text.Length;
        if (AssociatedObject.SelectionStart >= length)
            return true;

        if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
            AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;

        text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
        return true;
    }
    #endregion Auxiliary methods [PRIVATE] --------------------------------
}

Penggunaannya cukup mudah:

<i:Interaction.Behaviors>
    <behaviours:TextBoxInputRegExBehaviour RegularExpression="^\d+$" MaxLength="9" EmptyValue="0" />
</i:Interaction.Behaviors>
Alex Klaus
sumber
1
Solusi ini cukup baik. Tetapi Anda telah membuat kesalahan kecil: Ketika tidak mengatur kondisi MaxLengthAnda (this.MaxLength == 0 || text.Length <= this.MaxLength)kembali selalu falseketika menguji teks baru. Ini seharusnya lebih baik (this.MaxLength == int.MinValue || text.Length <= this.MaxLength)karena Anda menetapkan int.MinValuesebagai nilai default untuk MaxLength.
Christoph Meißner
1
Terima kasih @Christoph, ya, kamu benar. Saya telah memodifikasi jawaban saya.
Alex Klaus
@AlexKlaus ini berfungsi dengan baik sampai saya menambah UpdateSourceTrigger=PropertyChangedmengikat. Tahu cara membuat kode ini berfungsi saat mengubahUpdateSourceTrigger diatur ke PropertyChanged? Terima kasih telah membagikan kode ini.
Junior
32

Ini adalah cara yang sangat sederhana dan mudah untuk melakukan ini menggunakan MVVM.

Bind TextBox Anda dengan properti integer dalam model tampilan, dan ini akan bekerja seperti permata ... bahkan akan menunjukkan validasi ketika non-integer dimasukkan dalam kotak teks.

Kode XAML:

<TextBox x:Name="contactNoTxtBox"  Text="{Binding contactNo}" />

Lihat kode model:

private long _contactNo;
public long contactNo
{
    get { return _contactNo; }
    set
    {
        if (value == _contactNo)
            return;
        _contactNo = value;
        OnPropertyChanged();
    }
}
Snziv Gupta
sumber
Tetapi pertanyaannya berisi "Saya ingin menerima angka dan titik desimal" . Apakah titik desimal diterima untuk jawaban ini?
Peter Mortensen
Aku mencoba mengubah longke float, tapi itu tidak bekerja dengan benar dengan validasi langsung. Saya menambahkan UpdateSourceTrigger="PropertyChanged"ke ikatan, sehingga akan melakukan validasi karena setiap karakter diketik, dan tidak bisa lagi mengetikkan '.' di TextBox kecuali ada karakter ilegal hadir (harus mengetik "1x.234" lalu hapus 'x'). Rasanya juga agak lamban dalam mode ini. Ini tampaknya digunakan System.Number.ParseSingle()untuk melakukan pekerjaan, sehingga menerima berbagai notasi.
fadden
@wolle mungkin tidak terpilih karena tidak menjelaskan cara kerja validasi.
Paul McCarthy
26

Tambahkan ATURAN VALIDASI sehingga ketika teks berubah, periksa untuk menentukan apakah data itu numerik, dan jika ya, izinkan pemrosesan dilanjutkan, dan jika tidak, minta pengguna bahwa hanya data numerik yang diterima di bidang itu.

Baca selengkapnya di Validasi di Windows Presentation Foundation

Stephen Wrighton
sumber
6
Ini sebenarnya bukan jawaban untuk standar SO.
Robert Baker
Ini tampaknya menjadi cara bersih dari melakukannya.
Telemat
1
The adalah yang benar jawaban: validasi harus di Model viene atau model tingkat. Selain itu Anda hanya dapat mengikat ke tipe numerik seperti doubledan itu sudah memberi Anda validasi standar.
24

Toolkit WPF yang Diperluas memiliki satu: NumericUpDown masukkan deskripsi gambar di sini

Brian Lagunas
sumber
Saya sudah mencoba kontrol ini tetapi memberikan masalah ketika menggunakan spinner dengan UpdateSourceTrigger = PropertyChanged dan secara umum sulit bagi pengguna untuk memasukkan notasi ilmiah.
Menno Deij - van Rijswijk
5
Harap perhatikan bahwa NumericUpDownsekarang sudah usang. Anda dapat menggunakan DecimalUpDowndari toolkit yang diperbarui Extended WPF Toolkit ™ Community Edition
itsho
20

Bisa juga cukup menerapkan aturan validasi dan menerapkannya ke TextBox:

  <TextBox>
    <TextBox.Text>
      <Binding Path="OnyDigitInput" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <conv:OnlyDigitsValidationRule />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>

Dengan implementasi aturan sebagai berikut (menggunakan Regex yang sama seperti yang diusulkan dalam jawaban lain):

public class OnlyDigitsValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var validationResult = new ValidationResult(true, null);

        if(value != null)
        {
            if (!string.IsNullOrEmpty(value.ToString()))
            {
                var regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
                var parsingOk = !regex.IsMatch(value.ToString());
                if (!parsingOk)
                {
                    validationResult = new ValidationResult(false, "Illegal Characters, Please Enter Numeric Value");
                }
            }
        }

        return validationResult;
    }
}
baik-baik saja
sumber
Jika Anda ingin memasukkan angka desimal, jangan kembalikan "valid" ketika Teks berakhir dengan "." Silakan merujuk ke stackoverflow.com/a/27838893/417939
YantingChen
14

Di sini saya punya solusi sederhana yang terinspirasi oleh jawaban Ray . Ini harus cukup untuk mengidentifikasi segala bentuk angka.

Solusi ini juga dapat dengan mudah dimodifikasi jika Anda hanya menginginkan angka positif, nilai integer atau nilai yang akurat untuk jumlah maksimum tempat desimal, dll.


Seperti yang disarankan dalam jawaban Ray , Anda harus terlebih dahulu menambahkan PreviewTextInputacara:

<TextBox PreviewTextInput="TextBox_OnPreviewTextInput"/>

Kemudian letakkan yang berikut ini dalam kode di belakang:

private void TextBox_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
    var textBox = sender as TextBox;
    // Use SelectionStart property to find the caret position.
    // Insert the previewed text into the existing text in the textbox.
    var fullText = textBox.Text.Insert(textBox.SelectionStart, e.Text);

    double val;
    // If parsing is successful, set Handled to false
    e.Handled = !double.TryParse(fullText, out val);
}
Anthony
sumber
4
Saya suka jawaban ini banyak, sederhana dan efektif +
Pulle
tuhan dan sederhana namun jelek yang memungkinkan ruang
Momo
2
Ini masih memungkinkan seseorang untuk hanya menempelkan string ke dalam kotak teks
FCin
8

Saya mengizinkan nomor keypad numerik dan backspace:

    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        int key = (int)e.Key;

        e.Handled = !(key >= 34 && key <= 43 || 
                      key >= 74 && key <= 83 || 
                      key == 2);
    }
Hamzeh Soboh
sumber
8
Saya akan merekomendasikan menggunakan nilai enum daripada Magic Numbers :var keyEnum = (System.Windows.Input.Key) e.Key; e.Handled = !(keyEnum >= System.Windows.Input.Key.D0 && keyEnum <= System.Windows.Input.Key.D9 || keyEnum >= System.Windows.Input.Key.NumPad0 && keyEnum <= System.Windows.Input.Key.NumPad9 || keyEnum == System.Windows.Input.Key.Back);
itsho
7

Saya akan berasumsi bahwa:

  1. TextBox Anda yang ingin Anda izinkan input numerik hanya memiliki properti Text-nya yang awalnya disetel ke beberapa nilai angka yang valid (misalnya, 2.7172).

  2. Textbox Anda adalah anak dari jendela utama Anda

  3. Jendela utama Anda adalah kelas Window1

  4. Nama TextBox Anda adalah numericTB

Ide dasar:

  1. Tambahkan: private string previousText;ke kelas jendela utama Anda (Window1)

  2. Tambahkan: previousText = numericTB.Text;ke konstruktor jendela utama Anda

  3. Buat penangan untuk numericTB.TextChanged event menjadi sesuatu seperti ini:

    private void numericTB_TextChanged(object sender, TextChangedEventArgs e)
    {
        double num = 0;
        bool success = double.TryParse(((TextBox)sender).Text, out num);
        if (success & num >= 0)
            previousText = ((TextBox)sender).Text;
        else
            ((TextBox)sender).Text = previousText;
    }

Ini akan terus menetapkan Teks sebelumnya ke numericTB. Teks selama itu valid, dan mengatur numericTB. Teks ke nilai valid terakhir jika pengguna menulis sesuatu yang tidak Anda sukai. Tentu saja, ini hanya ide dasar, dan itu hanya "tahan idiot", bukan "bukti idiot". Itu tidak menangani kasus di mana pengguna mengacaukan ruang, misalnya. Jadi di sini adalah solusi lengkap yang saya pikir adalah "bukti idiot", dan jika saya salah tolong beri tahu saya:

  1. Konten file Window1.xaml Anda:

    <Window x:Class="IdiotProofNumericTextBox.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <TextBox Height="30" Width="100" Name="numericTB" TextChanged="numericTB_TextChanged"/>
        </Grid>
    </Window>
  2. Konten file Window.xaml.cs Anda:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace IdiotProofNumericTextBox
    {
        public partial class Window1 : Window
        {
            private string previousText;
    
            public Window1()
            {
                InitializeComponent();
                previousText = numericTB.Text;
            }
    
            private void numericTB_TextChanged(object sender, TextChangedEventArgs e)
            {
                if (string.IsNullOrEmpty(((TextBox)sender).Text))
                    previousText = "";
                else
                {
                    double num = 0;
                    bool success = double.TryParse(((TextBox)sender).Text, out num);
                    if (success & num >= 0)
                    {
                        ((TextBox)sender).Text.Trim();
                        previousText = ((TextBox)sender).Text;
                    }
                    else
                    {
                        ((TextBox)sender).Text = previousText;
                        ((TextBox)sender).SelectionStart = ((TextBox)sender).Text.Length;
                    }
                }
            }
        }
    }

Dan itu saja. Jika Anda memiliki banyak TextBox maka saya sarankan untuk membuat CustomControl yang mewarisi dari TextBox, sehingga Anda dapat membungkus sebelumnyaTeks dan numericTB_TextDirubah dalam file terpisah.

pengguna666535
sumber
Wow, ini luar biasa! Bagaimana saya bisa membiarkan simbol negatif di depan?
theNoobGuy
6

Ini adalah satu-satunya kode yang diperlukan:

void MyTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = new Regex("[^0-9]+").IsMatch(e.Text);
}

Ini hanya memungkinkan angka untuk dimasukkan ke dalam kotak teks.

Untuk mengizinkan titik desimal atau tanda minus, Anda dapat mengubah ekspresi reguler menjadi [^0-9.-]+.

Danny Beckett
sumber
1
Solusi yang sangat bagus kecuali untuk satu nitpick kecil: Ini tidak akan menghentikan Anda dari memasukkan spasi putih, karena itu tidak memicu acara PreviewTextInput.
Tim Pohlmann
Backspace tidak memecatnya juga.
Sayap Sendon
6

Jika Anda tidak ingin menulis banyak kode untuk melakukan fungsi dasar (saya tidak tahu mengapa orang membuat metode panjang) Anda bisa melakukan ini:

  1. Tambahkan namespace:

    using System.Text.RegularExpressions;
  2. Di XAML, setel properti TextChanged:

    <TextBox x:Name="txt1" TextChanged="txt1_TextChanged"/>
  3. Di WPF di bawah metode txt1_TextChanged, tambahkan Regex.Replace:

    private void txt1_TextChanged(object sender, TextChangedEventArgs e)
    {
        txt1.Text = Regex.Replace(txt1.Text, "[^0-9]+", "");
    }
iato
sumber
2
Jauh lebih bersih menggunakan Perilaku atau AttachedProperty. Tidak ada kode di belakang mengutak-atik setiap tampilan / untuk setiap kotak teks
Sir Rufo
Dapat bekerja tetapi jelek karena wortel akan melompat di posisi depan kotak teks
Momo
6

Pendekatan lain akan menggunakan perilaku terlampir, saya menerapkan TextBoxHelper kustom saya kelas , yang dapat digunakan pada kotak teks di seluruh proyek saya. Karena saya pikir bahwa berlangganan acara untuk setiap kotak teks dan di setiap file XAML individu untuk tujuan ini dapat memakan waktu.

Kelas TextBoxHelper yang saya implementasikan memiliki fitur-fitur ini:

  • Memfilter dan menerima hanya angka dalam Double , Int , Uint , dan Natural format
  • Memfilter dan hanya menerima Even atau Odd nomor
  • Menangani tempel pengendali acara untuk mencegah menempelkan teks yang tidak valid ke dalam kotak teks numerik kami
  • Dapat menetapkan Nilai Default yang akan digunakan untuk mencegah data yang tidak valid sebagai foto terakhir dengan berlangganan kotak teks acara TextChanged

Berikut ini adalah implementasi kelas TextBoxHelper:

public static class TextBoxHelper
{
    #region Enum Declarations

    public enum NumericFormat
    {
        Double,
        Int,
        Uint,
        Natural
    }

    public enum EvenOddConstraint
    {
        All,
        OnlyEven,
        OnlyOdd
    }

    #endregion

    #region Dependency Properties & CLR Wrappers

    public static readonly DependencyProperty OnlyNumericProperty =
        DependencyProperty.RegisterAttached("OnlyNumeric", typeof(NumericFormat?), typeof(TextBoxHelper),
            new PropertyMetadata(null, DependencyPropertiesChanged));
    public static void SetOnlyNumeric(TextBox element, NumericFormat value) =>
        element.SetValue(OnlyNumericProperty, value);
    public static NumericFormat GetOnlyNumeric(TextBox element) =>
        (NumericFormat) element.GetValue(OnlyNumericProperty);


    public static readonly DependencyProperty DefaultValueProperty =
        DependencyProperty.RegisterAttached("DefaultValue", typeof(string), typeof(TextBoxHelper),
            new PropertyMetadata(null, DependencyPropertiesChanged));
    public static void SetDefaultValue(TextBox element, string value) =>
        element.SetValue(DefaultValueProperty, value);
    public static string GetDefaultValue(TextBox element) => (string) element.GetValue(DefaultValueProperty);


    public static readonly DependencyProperty EvenOddConstraintProperty =
        DependencyProperty.RegisterAttached("EvenOddConstraint", typeof(EvenOddConstraint), typeof(TextBoxHelper),
            new PropertyMetadata(EvenOddConstraint.All, DependencyPropertiesChanged));
    public static void SetEvenOddConstraint(TextBox element, EvenOddConstraint value) =>
        element.SetValue(EvenOddConstraintProperty, value);
    public static EvenOddConstraint GetEvenOddConstraint(TextBox element) =>
        (EvenOddConstraint)element.GetValue(EvenOddConstraintProperty);

    #endregion

    #region Dependency Properties Methods

    private static void DependencyPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is TextBox textBox))
            throw new Exception("Attached property must be used with TextBox.");

        switch (e.Property.Name)
        {
            case "OnlyNumeric":
            {
                var castedValue = (NumericFormat?) e.NewValue;

                if (castedValue.HasValue)
                {
                    textBox.PreviewTextInput += TextBox_PreviewTextInput;
                    DataObject.AddPastingHandler(textBox, TextBox_PasteEventHandler);
                }
                else
                {
                    textBox.PreviewTextInput -= TextBox_PreviewTextInput;
                    DataObject.RemovePastingHandler(textBox, TextBox_PasteEventHandler);
                }

                break;
            }

            case "DefaultValue":
            {
                var castedValue = (string) e.NewValue;

                if (castedValue != null)
                {
                    textBox.TextChanged += TextBox_TextChanged;
                }
                else
                {
                    textBox.TextChanged -= TextBox_TextChanged;
                }

                break;
            }
        }
    }

    #endregion

    private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        var textBox = (TextBox)sender;

        string newText;

        if (textBox.SelectionLength == 0)
        {
            newText = textBox.Text.Insert(textBox.SelectionStart, e.Text);
        }
        else
        {
            var textAfterDelete = textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength);

            newText = textAfterDelete.Insert(textBox.SelectionStart, e.Text);
        }

        var evenOddConstraint = GetEvenOddConstraint(textBox);

        switch (GetOnlyNumeric(textBox))
        {
            case NumericFormat.Double:
            {
                if (double.TryParse(newText, out double number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Int:
            {
                if (int.TryParse(newText, out int number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Uint:
            {
                if (uint.TryParse(newText, out uint number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                e.Handled = true;
                            else
                                e.Handled = false;

                            break;
                    }
                }
                else
                    e.Handled = true;

                break;
            }

            case NumericFormat.Natural:
            {
                if (uint.TryParse(newText, out uint number))
                {
                    if (number == 0)
                        e.Handled = true;
                    else
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;

                                break;
                        }
                    }
                }
                else
                    e.Handled = true;

                break;
            }
        }
    }

    private static void TextBox_PasteEventHandler(object sender, DataObjectPastingEventArgs e)
    {
        var textBox = (TextBox)sender;

        if (e.DataObject.GetDataPresent(typeof(string)))
        {
            var clipboardText = (string) e.DataObject.GetData(typeof(string));

            var newText = textBox.Text.Insert(textBox.SelectionStart, clipboardText);

            var evenOddConstraint = GetEvenOddConstraint(textBox);

            switch (GetOnlyNumeric(textBox))
            {
                case NumericFormat.Double:
                {
                    if (double.TryParse(newText, out double number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();

                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Int:
                {
                    if (int.TryParse(newText, out int number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();


                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Uint:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    e.CancelCommand();

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    e.CancelCommand();


                                break;
                        }
                    }
                    else
                        e.CancelCommand();

                    break;
                }

                case NumericFormat.Natural:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        if (number == 0)
                            e.CancelCommand();
                        else
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:

                                    if (number % 2 != 0)
                                        e.CancelCommand();

                                    break;

                                case EvenOddConstraint.OnlyOdd:

                                    if (number % 2 == 0)
                                        e.CancelCommand();

                                    break;
                            }
                        }
                    }
                    else
                    {
                        e.CancelCommand();
                    }

                    break;
                }
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    private static void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var textBox = (TextBox)sender;

        var defaultValue = GetDefaultValue(textBox);

        var evenOddConstraint = GetEvenOddConstraint(textBox);

        switch (GetOnlyNumeric(textBox))
        {
            case NumericFormat.Double:
            {
                if (double.TryParse(textBox.Text, out double number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Int:
            {
                if (int.TryParse(textBox.Text, out int number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Uint:
            {
                if (uint.TryParse(textBox.Text, out uint number))
                {
                    switch (evenOddConstraint)
                    {
                        case EvenOddConstraint.OnlyEven:

                            if (number % 2 != 0)
                                textBox.Text = defaultValue;

                            break;

                        case EvenOddConstraint.OnlyOdd:

                            if (number % 2 == 0)
                                textBox.Text = defaultValue;

                            break;
                    }
                }
                else
                    textBox.Text = defaultValue;

                break;
            }

            case NumericFormat.Natural:
            {
                if (uint.TryParse(textBox.Text, out uint number))
                {
                    if(number == 0)
                        textBox.Text = defaultValue;
                    else
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:

                                if (number % 2 != 0)
                                    textBox.Text = defaultValue;

                                break;

                            case EvenOddConstraint.OnlyOdd:

                                if (number % 2 == 0)
                                    textBox.Text = defaultValue;

                                break;
                        }
                    }
                }
                else
                {
                    textBox.Text = defaultValue;
                }

                break;
            }
        }
    }
}

Dan inilah beberapa contoh penggunaannya yang mudah:

<TextBox viewHelpers:TextBoxHelper.OnlyNumeric="Double"
         viewHelpers:TextBoxHelper.DefaultValue="1"/>

Atau

<TextBox viewHelpers:TextBoxHelper.OnlyNumeric="Natural"
         viewHelpers:TextBoxHelper.DefaultValue="3"
         viewHelpers:TextBoxHelper.EvenOddConstraint="OnlyOdd"/>

Perhatikan bahwa TextBoxHelper saya berada di viewHelpers xmlns alias.

Saya harap implementasi ini memudahkan pekerjaan orang lain :)

Amir Mahdi Nassiri
sumber
1
Ini bagus ketika menggunakan kotak teks di dalam DataTemplate, terima kasih!
NucS
3
Jawaban yang bagus tetapi saya menemukan metode Anda sulit dibaca. Mungkin Anda harus memecahnya menjadi yang lebih kecil. Lihat Berapa panjang ideal suatu metode untuk Anda?
Anthony
Terima kasih atas umpan balik konstruktif @Anthony
Amir Mahdi Nassiri
4
e.Handled = (int)e.Key >= 43 || (int)e.Key <= 34;

di acara keydown preview kotak teks.

Pemula
sumber
3
Tidak mengizinkan backspace.
sventevit
2
Backspace adalah 2, tab 3
Daniel
6
-1 karena dalam pengalaman saya trik cerdas semacam ini pada akhirnya menggigit Anda, seperti dicatat beberapa komentator lainnya.
DonkeyMaster
Panah kiri adalah 23, Panah kanan adalah 25.
Aaron
4
PreviewTextInput += (s, e) =>
{
    e.Handled = !e.Text.All(char.IsDigit);
};
Julian Kowalczuk
sumber
2
ini juga tidak akan menerima titik ., karena e.Texthanya mengembalikan karakter input terakhir dan sebuah titik akan gagal dalam IsDigitpemeriksaan.
Anthony
4

Bagi mereka yang mencari implementasi cepat dan sangat sederhana untuk jenis masalah ini hanya menggunakan bilangan bulat dan desimal, dalam file XAML Anda, tambahkan PreviewTextInputproperti ke Anda TextBoxdan kemudian dalam file xaml.cs Anda gunakan:

private void Text_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !char.IsDigit(e.Text.Last()) && !e.Text.Last() == '.';
}

Ini agak berlebihan untuk terus memeriksa seluruh string setiap kali kecuali, seperti yang orang lain katakan, Anda melakukan sesuatu dengan notasi ilmiah (meskipun, jika Anda menambahkan karakter tertentu seperti 'e', ​​regex sederhana yang menambahkan simbol / karakter adalah sangat sederhana dan diilustrasikan dalam jawaban lain). Tetapi untuk nilai floating point sederhana, solusi ini sudah cukup.

Ditulis sebagai one-liner dengan ekspresi lambda:

private void Text_PreviewTextInput(object sender, TextCompositionEventArgs e) => e.Handled = !char.IsDigit(e.Text.Last() && !e.Text.Last() == '.');
Chris
sumber
3

Kita dapat melakukan validasi pada event yang diubah kotak teks. Implementasi berikut ini mencegah input penekanan tombol selain dari angka dan satu angka desimal.

private void textBoxNumeric_TextChanged(object sender, TextChangedEventArgs e) 
{         
      TextBox textBox = sender as TextBox;         
      Int32 selectionStart = textBox.SelectionStart;         
      Int32 selectionLength = textBox.SelectionLength;         
      String newText = String.Empty;         
      int count = 0;         
      foreach (Char c in textBox.Text.ToCharArray())         
      {             
         if (Char.IsDigit(c) || Char.IsControl(c) || (c == '.' && count == 0))             
         {                 
            newText += c;                 
            if (c == '.')                     
              count += 1;             
         }         
     }         
     textBox.Text = newText;         
     textBox.SelectionStart = selectionStart <= textBox.Text.Length ? selectionStart :        textBox.Text.Length;     
} 
kumar Gouraw
sumber
3

Bagaimana dengan ini? Bekerja dengan baik untuk saya. Berharap saya tidak melewatkan kasus tepi ...

MyTextBox.PreviewTextInput += (sender, args) =>
{
    if (!int.TryParse(args.Text, out _))
    {
        args.Handled = true;
    }
};

DataObject.AddPastingHandler(MyTextBox, (sender, args) =>
{
    var isUnicodeText = args.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
    if (!isUnicodeText)
    {
        args.CancelCommand();
    }

    var data = args.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
    if (!int.TryParse(data, out _))
    {
        args.CancelCommand();
    }
});
Shahin Dohan
sumber
2

Dalam Formulir Windows itu mudah; Anda dapat menambahkan acara untuk KeyPress dan semuanya bekerja dengan mudah. Namun, di WPF acara itu tidak ada. Tetapi ada cara yang lebih mudah untuk itu.

WPF TextBox memiliki acara TextChanged yang umum untuk semuanya. Itu termasuk menempel, mengetik, dan apa pun yang bisa muncul di pikiran Anda.

Jadi Anda dapat melakukan sesuatu seperti ini:

XAML:

<TextBox name="txtBox1" ... TextChanged="TextBox_TextChanged"/>

KODE DI BALIK:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e) {
    string s = Regex.Replace(((TextBox)sender).Text, @"[^\d.]", "");
    ((TextBox)sender).Text = s;
}

Ini juga menerima ., jika Anda tidak menginginkannya, hapus saja dari regexpernyataan yang ada @[^\d].

Catatan : Acara ini dapat digunakan pada banyak TextBox'es karena menggunakan senderTeks objek. Anda hanya menulis acara sekali dan dapat menggunakannya untuk beberapa TextBox'es.

Semua orang
sumber
2

Sekarang saya tahu pertanyaan ini memiliki jawaban yang diterima , tetapi secara pribadi, saya merasa sedikit membingungkan dan saya percaya seharusnya lebih mudah dari itu. Jadi saya akan mencoba menunjukkan bagaimana saya membuatnya bekerja sebaik mungkin:

Di Windows Forms , ada acara yang disebut KeyPressyang sangat baik untuk tugas semacam ini. Tapi itu tidak ada di WPF , jadi sebagai gantinya, kami akan menggunakan PreviewTextInputacara tersebut. Juga, untuk validasi, saya percaya seseorang dapat menggunakan a foreachuntuk mengulangi textbox.Textdan mengecek apakah cocok ;) kondisinya, tapi jujur, ini adalah ekspresi reguler digunakan untuk .

Satu hal lagi sebelum kita menyelami kode suci . Agar acara dipecat, seseorang dapat melakukan dua hal:

  1. Gunakan XAML untuk memberi tahu program yang fungsinya memanggil: <PreviewTextInput="textBox_PreviewTextInput/>
  2. Lakukan jika Loadedterjadi form (di mana textBox berada): textBox.PreviewTextInput += onlyNumeric;

Saya pikir metode kedua lebih baik karena dalam situasi seperti ini, sebagian besar Anda akan diminta untuk menerapkan kondisi yang sama ( regex) ke lebih dari satu TextBoxdan Anda tidak ingin mengulangi sendiri!.

Akhirnya, inilah cara Anda melakukannya:

private void onlyNumeric(object sender, TextCompositionEventArgs e)
{
    string onlyNumeric = @"^([0-9]+(.[0-9]+)?)$";
    Regex regex = new Regex(onlyNumeric);
    e.Handled = !regex.IsMatch(e.Text);
}
Amir A. Shabani
sumber
2

Ini versi saya. Ini didasarkan pada ValidatingTextBoxkelas dasar yang hanya membatalkan apa yang telah dilakukan jika tidak "valid". Ini mendukung tempel, potong, hapus, backspace, +, - dll.

Untuk integer 32-bit, ada kelas Int32TextBox yang hanya membandingkan dengan int. Saya juga menambahkan kelas validasi floating point.

public class ValidatingTextBox : TextBox
{
    private bool _inEvents;
    private string _textBefore;
    private int _selectionStart;
    private int _selectionLength;

    public event EventHandler<ValidateTextEventArgs> ValidateText;

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        if (_inEvents)
            return;

        _selectionStart = SelectionStart;
        _selectionLength = SelectionLength;
        _textBefore = Text;
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        if (_inEvents)
            return;

        _inEvents = true;
        var ev = new ValidateTextEventArgs(Text);
        OnValidateText(this, ev);
        if (ev.Cancel)
        {
            Text = _textBefore;
            SelectionStart = _selectionStart;
            SelectionLength = _selectionLength;
        }
        _inEvents = false;
    }

    protected virtual void OnValidateText(object sender, ValidateTextEventArgs e) => ValidateText?.Invoke(this, e);
}

public class ValidateTextEventArgs : CancelEventArgs
{
    public ValidateTextEventArgs(string text) => Text = text;

    public string Text { get; }
}

public class Int32TextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !int.TryParse(e.Text, out var value);
}

public class Int64TextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !long.TryParse(e.Text, out var value);
}

public class DoubleTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !double.TryParse(e.Text, out var value);
}

public class SingleTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !float.TryParse(e.Text, out var value);
}

public class DecimalTextBox : ValidatingTextBox
{
    protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !decimal.TryParse(e.Text, out var value);
}

Catatan 1: Saat menggunakan pengikatan WPF, Anda harus memastikan bahwa Anda menggunakan kelas yang cocok dengan tipe properti terikat, jika tidak, ini dapat menyebabkan hasil yang aneh.

Catatan 2: Saat menggunakan kelas floating point dengan pengikatan WPF, pastikan pengikatan menggunakan budaya saat ini untuk mencocokkan metode TryParse yang saya gunakan.

Simon Mourier
sumber
1

Menggunakan:

Private Sub DetailTextBox_PreviewTextInput( _
  ByVal sender As Object, _
  ByVal e As System.Windows.Input.TextCompositionEventArgs) _
  Handles DetailTextBox.PreviewTextInput

    If _IsANumber Then
        If Not Char.IsNumber(e.Text) Then
            e.Handled = True
        End If
    End If
End Sub
Johnny
sumber
Penjelasan akan diurutkan.
Peter Mortensen
1

Saya bekerja dengan kotak tidak terikat untuk proyek sederhana yang sedang saya kerjakan, jadi saya tidak bisa menggunakan pendekatan penjilidan standar. Karenanya saya membuat peretasan sederhana yang mungkin cukup berguna bagi orang lain dengan hanya memperluas kontrol TextBox yang ada:

namespace MyApplication.InterfaceSupport
{
    public class NumericTextBox : TextBox
    {


        public NumericTextBox() : base()
        {
            TextChanged += OnTextChanged;
        }


        public void OnTextChanged(object sender, TextChangedEventArgs changed)
        {
            if (!String.IsNullOrWhiteSpace(Text))
            {
                try
                {
                    int value = Convert.ToInt32(Text);
                }
                catch (Exception e)
                {
                    MessageBox.Show(String.Format("{0} only accepts numeric input.", Name));
                    Text = "";
                }
            }
        }


        public int? Value
        {
            set
            {
                if (value != null)
                {
                    this.Text = value.ToString();
                }
                else 
                    Text = "";
            }
            get
            {
                try
                {
                    return Convert.ToInt32(this.Text);
                }
                catch (Exception ef)
                {
                    // Not numeric.
                }
                return null;
            }
        }
    }
}

Tentunya, untuk tipe mengambang, Anda ingin menguraikannya sebagai pelampung dan sebagainya. Prinsip yang sama berlaku.

Kemudian dalam file XAML Anda perlu memasukkan namespace yang relevan:

<UserControl x:Class="MyApplication.UserControls.UnParameterisedControl"
             [ Snip ]
             xmlns:interfaceSupport="clr-namespace:MyApplication.InterfaceSupport"
             >

Setelah itu Anda dapat menggunakannya sebagai kontrol biasa:

<interfaceSupport:NumericTextBox Height="23" HorizontalAlignment="Left" Margin="168,51,0,0" x:Name="NumericBox" VerticalAlignment="Top" Width="120" >
glenatron
sumber
1

Setelah menggunakan beberapa solusi di sini untuk beberapa waktu, saya mengembangkan sendiri yang berfungsi dengan baik untuk pengaturan MVVM saya. Perhatikan bahwa ini tidak sedinamis beberapa yang lain dalam arti masih memungkinkan pengguna untuk memasukkan karakter yang salah, tetapi menghalangi mereka dari menekan tombol dan dengan demikian melakukan apa saja. Ini berjalan dengan baik dengan tema saya tombol abu-abu ketika tindakan tidak dapat dilakukan.

Saya memiliki seorang TextBoxpengguna yang harus memasukkan sejumlah halaman dokumen yang akan dicetak:

<TextBox Text="{Binding NumberPagesToPrint, UpdateSourceTrigger=PropertyChanged}"/>

... dengan properti yang mengikat ini:

private string _numberPagesToPrint;
public string NumberPagesToPrint
{
    get { return _numberPagesToPrint; }
    set
    {
        if (_numberPagesToPrint == value)
        {
            return;
        }

        _numberPagesToPrint = value;
        OnPropertyChanged("NumberPagesToPrint");
    }
}

Saya juga punya tombol:

<Button Template="{DynamicResource CustomButton_Flat}" Content="Set"
        Command="{Binding SetNumberPagesCommand}"/>

... dengan perintah ini mengikat:

private RelayCommand _setNumberPagesCommand;
public ICommand SetNumberPagesCommand
{
    get
    {
        if (_setNumberPagesCommand == null)
        {
            int num;
            _setNumberPagesCommand = new RelayCommand(param => SetNumberOfPages(),
                () => Int32.TryParse(NumberPagesToPrint, out num));
        }

        return _setNumberPagesCommand;
    }
}

Dan kemudian ada metode SetNumberOfPages(), tetapi tidak penting untuk topik ini. Ini berfungsi dengan baik dalam kasus saya karena saya tidak perlu menambahkan kode apa pun ke dalam file di belakang kode Tampilan dan memungkinkan saya untuk mengontrol perilaku menggunakan Commandproperti.

BK
sumber
1

Di aplikasi WPF, Anda dapat menangani ini dengan menangani TextChangedacara:

void arsDigitTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
    Regex regex = new Regex("[^0-9]+");
    bool handle = regex.IsMatch(this.Text);
    if (handle)
    {
        StringBuilder dd = new StringBuilder();
        int i = -1;
        int cursor = -1;
        foreach (char item in this.Text)
        {
            i++;
            if (char.IsDigit(item))
                dd.Append(item);
            else if(cursor == -1)
                cursor = i;
        }
        this.Text = dd.ToString();

        if (i == -1)
            this.SelectionStart = this.Text.Length;
        else
            this.SelectionStart = cursor;
    }
}
Mehdi Khademloo
sumber
1

Untuk pengembang yang ingin bidang teksnya hanya menerima nomor yang tidak ditandai seperti port soket dan sebagainya:

WPF

<TextBox PreviewTextInput="Port_PreviewTextInput" MaxLines="1"/>

C #

private void Port_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    e.Handled = !int.TryParse(e.Text, out int x);
}
Beyondo
sumber
2
Perhatikan bahwa jika Anda benar-benar ingin menggunakan metode ini dengan bidang port soket; Anda harus memeriksa apakah bilangan bulat kurang dari atau sama dengan 65535. Jika lebih besar maka itu bukan port yang valid. Juga, mengatur TextBox.MaxLengthuntuk 5akan membantu baik secara program atau XAML .
Beyondo
0

Inilah yang akan saya gunakan untuk mendapatkan kotak teks WPF yang menerima angka dan titik desimal:

class numericTextBox : TextBox
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        bool b = false;
        switch (e.Key)
        {
            case Key.Back: b = true; break;
            case Key.D0: b = true; break;
            case Key.D1: b = true; break;
            case Key.D2: b = true; break;
            case Key.D3: b = true; break;
            case Key.D4: b = true; break;
            case Key.D5: b = true; break;
            case Key.D6: b = true; break;
            case Key.D7: b = true; break;
            case Key.D8: b = true; break;
            case Key.D9: b = true; break;
            case Key.OemPeriod: b = true; break;
        }
        if (b == false)
        {
            e.Handled = true;
        }
        base.OnKeyDown(e);
    }
}

Masukkan kode ke file kelas baru, tambahkan

using System.Windows.Controls;
using System.Windows.Input;

di bagian atas file dan bangun solusinya. Kontrol numericTextBox kemudian akan muncul di bagian atas kotak alat.

matsolof
sumber
1
Lihat solusi JAUH lebih mudah sebelumnya menggunakan NumberValidationTextBox dan ekspresi reguler. Ini konyol.
Scott Shaw-Smith
@ ScottShaw-Smith Mungkin solusi yang diterima kurang kode, tetapi tidak lebih cepat dari ini. Selalu ada beberapa proyek yang membutuhkan banyak kekuatan pemrosesan daripada menggunakan regex.
Beyondo