C# 如何让 TextBox 只接受 WPF 中的数字输入?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1268552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:28:02  来源:igfitidea点击:

How do I get a TextBox to only accept numeric input in WPF?

c#wpfxamltextboxnumericupdown

提问by Giffyguy

I'm looking to accept digits and the decimal point, but no sign.

我希望接受数字和小数点,但没有符号。

I've looked at samples using the NumericUpDown control for Windows Forms, and this sample of a NumericUpDown custom control from Microsoft. But so far it seems like NumericUpDown (supported by WPF or not) is not going to provide the functionality that I want. The way my application is designed, nobody in their right mind is going to want to mess with the arrows. They don't make any practical sense, in the context of my application.

我查看了使用 Windows 窗体的 NumericUpDown 控件的示例,以及来自 Microsoft 的 NumericUpDown 自定义控件的示例。但到目前为止,似乎 NumericUpDown(是否受 WPF 支持)不会提供我想要的功能。我的应用程序的设计方式,没有人会想弄乱箭头。在我的应用程序中,它们没有任何实际意义。

So I'm looking for a simple way to make a standard WPF TextBox accept only the characters that I want. Is this possible? Is it practical?

所以我正在寻找一种简单的方法来使标准 WPF TextBox 只接受我想要的字符。这可能吗?实用吗?

采纳答案by Ray

Add a preview text input event. Like so: <TextBox PreviewTextInput="PreviewTextInput" />.

添加预览文本输入事件。像这样:<TextBox PreviewTextInput="PreviewTextInput" />

Then inside that set the e.Handledif the text isn't allowed. e.Handled = !IsTextAllowed(e.Text);

然后在里面设置e.Handled如果不允许文本。e.Handled = !IsTextAllowed(e.Text);

I use a simple regex in IsTextAllowedmethod to see if I should allow what they've typed. In my case I only want to allow numbers, dots and dashes.

我在IsTextAllowed方法中使用一个简单的正则表达式来查看我是否应该允许他们输入的内容。就我而言,我只想允许数字、点和破折号。

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

If you want to prevent pasting of incorrect data hook up the DataObject.Pastingevent DataObject.Pasting="TextBoxPasting"as shown here(code excerpted):

如果您想防止粘贴不正确的数据,请按照此处所示连接DataObject.Pasting事件(代码摘录):DataObject.Pasting="TextBoxPasting"

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

回答by Stephen Wrighton

Add in a VALIDATION RULE so that when the text changes, check to determine if the data is numeric, and if it is, allows processing to continue, and if it is not, prompts the user that only numeric data is accepted in that field.

添加验证规则,以便当文本更改时,检查以确定数据是否为数字,如果是,则允许处理继续,如果不是,则提示用户该字段中仅接受数字数据。

Read more in Validation in Windows Presentation Foundation

在 Windows Presentation Foundation中的验证中阅读更多信息

回答by Brian Lagunas

The Extented WPF Toolkit has one: NumericUpDownenter image description here

扩展 WPF 工具包有一个:NumericUpDown在此处输入图片说明

回答by user666535

I will assume that:

我会假设:

  1. Your TextBox for which you want to allow numeric input only has its Text property initially set to some valid number value (for example, 2.7172).

  2. Your Textbox is a child of your main window

  3. Your main window is of class Window1

  4. Your TextBox name is numericTB

  1. 您希望允许数字输入的 TextBox 仅将其 Text 属性初始设置为某个有效数字值(例如,2.7172)。

  2. 您的文本框是主窗口的子项

  3. 您的主窗口属于 Window1 类

  4. 您的文本框名称是 numericTB

Basic idea:

基本思路:

  1. Add: private string previousText;to your main window class (Window1)

  2. Add: previousText = numericTB.Text;to your main window constructor

  3. Create a handler for the numericTB.TextChanged event to be something like this:

    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;
    }
    
  1. 添加:private string previousText;到您的主窗口类(Window1)

  2. 添加:previousText = numericTB.Text;到您的主窗口构造函数

  3. 为 numericTB.TextChanged 事件创建一个处理程序,如下所示:

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

This will keep setting previousText to numericTB.Text as long as it is valid, and set numericTB.Text to its last valid value if the user writes something that you don't like. Of course, this is just basic idea, and it is just "idiot resistant", not "idiot proof". It doesn't handle the case in which the user messes with spaces, for example. So here is a complete solution which I think is "idiot proof", and if I'm wrong please tell me:

只要它有效,这将继续将 previousText 设置为 numericTB.Text,如果用户写了一些您不喜欢的内容,则将 numericTB.Text 设置为其最后一个有效值。当然,这只是基本思路,只是“抗白痴”,不是“防白痴”。例如,它不处理用户弄乱空格的情况。所以这是一个完整的解决方案,我认为它是“白痴证明”,如果我错了,请告诉我:

  1. Content of your Window1.xaml file:

    <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. Content of your Window.xaml.cs file:

    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;
                    }
                }
            }
        }
    }
    
  1. Window1.xaml 文件的内容:

    <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. Window.xaml.cs 文件的内容:

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

And that's it. If you have many TextBoxes then I recommend creating a CustomControl that inherits from TextBox, so you can wrap previousText and numericTB_TextChanged up in a separate file.

就是这样。如果您有很多 TextBox,那么我建议您创建一个继承自 TextBox 的 CustomControl,这样您就可以将 previousText 和 numericTB_TextChanged 包装在一个单独的文件中。

回答by Novice

e.Handled = (int)e.Key >= 43 || (int)e.Key <= 34;

in preview keydown event of textbox.

在文本框的预览 keydown 事件中。

回答by Johnny

Use:

用:

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

回答by Wil P

I used some of what was already here and put my own twist on it using a behavior so I don't have to propagate this code throughout a ton of Views...

我使用了这里已经存在的一些内容,并使用一种行为对其进行了自己的修改,因此我不必在大量视图中传播此代码...

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

Here is the relevant view code:

这是相关的视图代码:

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

回答by kumar Gouraw

We can do validation on text box changed event. The following implementation prevents keypress input other than numeric and one decimal point.

我们可以对文本框更改事件进行验证。以下实现可防止数字和一位小数点以外的按键输入。

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

回答by Kishor

The event handler is previewing text input. Here a regular expression matches the text input only if it is not a number, and then it is not made to entry textbox.

事件处理程序正在预览文本输入。这里的正则表达式仅在文本输入不是数字时才匹配它,然后它不会进入输入文本框。

If you want only letters then replace the regular expression as [^a-zA-Z].

如果您只想要字母,则将正则表达式替换为[^a-zA-Z].

XAML

XAML

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

XAML.CS 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);
}

回答by glenatron

I was working with an unbound box for a simple project I was working on, so I couldn't use the standard binding approach. Consequently I created a simple hack that others might find quite handy by simply extending the existing TextBox control:

我正在为我正在处理的一个简单项目使用未绑定的框,因此我无法使用标准绑定方法。因此,我创建了一个简单的 hack,通过简单地扩展现有的 TextBox 控件,其他人可能会发现它非常方便:

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

Obviously, for a floating type, you would want to parse it as a float and so on. The same principles apply.

显然,对于浮动类型,您可能希望将其解析为浮点数等等。同样的原则也适用。

Then in the XAML file you need to include the relevant namespace:

然后在 XAML 文件中,您需要包含相关的命名空间:

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

After that you can use it as a regular control:

之后,您可以将其用作常规控件:

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