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

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

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


当前回答

在Windows窗体中,这很容易;你可以添加一个事件按键和一切工作轻松。然而,在WPF中该事件不存在。但是有一个更简单的方法。

WPF文本框有TextChanged事件,这是一般的一切。它包括粘贴,输入和任何你能想到的东西。

所以你可以这样做:

XAML:

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

背后的代码:

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

这也是可以接受的。,如果你不想要它,只需将它从正则表达式语句中删除为@[^\d]。

注意:此事件可以用于许多TextBox元素,因为它使用发送方对象的文本。您只需编写一次事件,并且可以将其用于多个TextBox元素。

其他回答

对于那些寻找一个快速和非常简单的实现这种类型的问题,只使用整数和小数,在你的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 PreviewTextInput="PreviewTextInput" />。

然后在这个set中,如果文本不被允许,e。handled。e.Handled = ! istextallows (e.Text);

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

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

如果您希望防止粘贴不正确的数据,请连接数据对象。粘贴事件数据对象。粘贴="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();
    }
}

这是我用来获得一个接受数字和小数点的WPF文本框:

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

将代码放在一个新的类文件中,添加

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

并构建解决方案。numericTextBox控件将出现在工具箱的顶部。

这是我的版本。它基于一个基本的ValidatingTextBox类,如果它不是“有效”的,它只是撤销已经做过的事情。它支持粘贴,剪切,删除,退格,+,-等。

对于32位整型,有一个Int32TextBox类用于与整型进行比较。我还添加了浮点验证类。

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

注意1:在使用WPF绑定时,必须确保使用符合绑定属性类型的类,否则可能会导致奇怪的结果。

注意2:在WPF绑定中使用浮点类时,请确保绑定使用当前区域性来匹配我使用的TryParse方法。

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

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

    }