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

我已经看过使用Windows窗体中的NumericUpDown控件的示例,以及来自微软的这个NumericUpDown自定义控件的示例。但到目前为止,似乎NumericUpDown (WPF是否支持)不会提供我想要的功能。我的应用程序是这样设计的,任何头脑正常的人都不会想弄乱箭头。在我的应用程序中,它们没有任何实际意义。

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


当前回答

对于那些寻找一个快速和非常简单的实现这种类型的问题,只使用整数和小数,在你的XAML文件,添加一个PreviewTextInput属性到你的textbox,然后在你的XAML .cs文件使用:

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

每次都检查整个字符串有点多余,除非像其他人提到的那样,你正在使用科学符号(尽管,如果你添加某些字符,如'e',一个添加符号/字符的简单正则表达式非常简单,并在其他答案中说明)。但是对于简单的浮点值,这个解决方案就足够了。

编写为带有lambda表达式的一行代码:

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

其他回答

也可以简单地实现一个验证规则,并将其应用到TextBox:

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

实现如下规则(使用与其他答案中建议的相同的Regex):

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

下面的代码创建了一个控件,你将能够像正常的文本框一样使用,但它只会把一个正的双精度作为输入:

在XAML中,你可以这样使用这个控件:

<local:UnsignedDoubleBox/>

在c#代码中,在当前命名空间中添加以下内容:

public class UnsignedDoubleBox : TextBox
    {
        public UnsignedDoubleBox()
        {
            this.PreviewTextInput += defaultPreviewTextInput;
            DataObject.AddPastingHandler(this, defaultTextBoxPasting);
        }

        private bool IsTextAllowed(TextBox textBox, String text)
        {
            //source: https://stackoverflow.com/questions/23397195/in-wpf-does-previewtextinput-always-give-a-single-character-only#comment89374810_23406386
            String newText = textBox.Text.Insert(textBox.CaretIndex, text);
            double res;
            return double.TryParse(newText, out res) && res >= 0;
        }
        //source: https://stackoverflow.com/a/1268648/13093413
        private void defaultTextBoxPasting(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(typeof(String)))
            {
                String text = (String)e.DataObject.GetData(typeof(String));

                if (!IsTextAllowed((TextBox)sender, text))
                {
                    e.CancelCommand();
                }
            }
            else
            {
                e.CancelCommand();
            }
        }

        private void defaultPreviewTextInput(object sender, TextCompositionEventArgs e)
        {

            if (IsTextAllowed((TextBox)sender, e.Text))
            {
                e.Handled = false;
            }
            else
            {
                e.Handled = true;
            }
        }

    }

在使用这里的一些解决方案一段时间后,我开发了自己的解决方案,该解决方案适用于我的MVVM设置。注意,在允许用户输入错误字符的意义上,它不像其他一些那样动态,但它阻止用户按下按钮,从而阻止他们做任何事情。这很好地配合了我的主题,即当操作无法执行时将按钮变灰。

我有一个文本框,用户必须输入一些文档页面要打印:

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

...使用这个绑定属性:

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

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

我还有一个按钮:

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

...使用此命令绑定:

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

        return _setNumberPagesCommand;
    }
}

然后是SetNumberOfPages()方法,但对于本主题不重要。它在我的案例中工作得很好,因为我不需要向视图的代码隐藏文件中添加任何代码,并且它允许我使用Command属性控制行为。

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

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

XAML

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

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

受雷的启发,我有一个简单的解决方案。这应该足以识别任何形式的数字。

如果您只想要正数、整数值或精确到小数点后最大位数的值,则可以轻松修改此解决方案。


正如Ray的回答所建议的,你需要首先添加一个PreviewTextInput事件:

<TextBox PreviewTextInput="TextBox_OnPreviewTextInput"/>

然后把下面的代码放在后面:

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

对于无效的空格,我们可以添加NumberStyles:

using System.Globalization;

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, 
                                 NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, 
                                 CultureInfo.InvariantCulture,
                                 out val);
}