You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Avalonia的NumericUpDown输入时仅允许数字?

解决方案

方法1:用附加属性实现全局数字过滤(推荐)

这种方式可以复用在任意TextBox或基于TextBox的控件上,不用重复编写验证逻辑。

1. 创建附加属性类

using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using System.Text.RegularExpressions;

public static class NumericInputHelper
{
    public static readonly AttachedProperty<bool> IsNumericOnlyProperty =
        AvaloniaProperty.RegisterAttached<NumericInputHelper, Control, bool>(
            "IsNumericOnly", defaultValue: false);

    public static bool GetIsNumericOnly(Control obj)
    {
        return obj.GetValue(IsNumericOnlyProperty);
    }

    public static void SetIsNumericOnly(Control obj, bool value)
    {
        obj.SetValue(IsNumericOnlyProperty, value);
    }

    static NumericInputHelper()
    {
        IsNumericOnlyProperty.Changed.Subscribe(e =>
        {
            // 处理普通TextBox
            if (e.Sender is TextBox textBox)
            {
                ToggleNumericFilter(textBox, (bool)e.NewValue);
            }
            // 兼容NumericUpDown,获取其内部的TextBox
            else if (e.Sender is NumericUpDown upDown)
            {
                upDown.Loaded += (s, args) =>
                {
                    if (upDown.FindDescendant<TextBox>() is TextBox innerTextBox)
                    {
                        ToggleNumericFilter(innerTextBox, (bool)e.NewValue);
                    }
                };
            }
        });
    }

    private static void ToggleNumericFilter(TextBox textBox, bool enable)
    {
        if (enable)
        {
            textBox.TextChanged += OnTextBoxTextChanged;
            textBox.PreviewKeyDown += OnTextBoxPreviewKeyDown;
        }
        else
        {
            textBox.TextChanged -= OnTextBoxTextChanged;
            textBox.PreviewKeyDown -= OnTextBoxPreviewKeyDown;
        }
    }

    private static void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
    {
        if (sender is not TextBox textBox) return;

        // 过滤非数字字符,仅保留整数
        var filteredText = Regex.Replace(textBox.Text ?? string.Empty, @"[^0-9]", string.Empty);
        if (filteredText != textBox.Text)
        {
            // 记录并恢复光标位置,避免过滤后光标跳至开头
            var caretIndex = textBox.CaretIndex;
            var selectionStart = textBox.SelectionStart;
            var selectionLength = textBox.SelectionLength;

            textBox.Text = filteredText;

            textBox.CaretIndex = Math.Min(caretIndex, filteredText.Length);
            textBox.SelectionStart = Math.Min(selectionStart, filteredText.Length);
            textBox.SelectionLength = selectionLength;
        }
    }

    private static void OnTextBoxPreviewKeyDown(object sender, KeyEventArgs e)
    {
        // 禁止输入小数点、正负号等非整数按键
        if (e.Key is Key.Decimal or Key.Subtract or Key.Add)
        {
            e.Handled = true;
        }
    }
}

2. 在XAML中使用

给普通TextBox应用:

<TextBox local:NumericInputHelper.IsNumericOnly="True" 
         Text="{Binding Samples, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

给NumericUpDown应用:

<NumericUpDown Value="{Binding Samples}" 
               ParsingNumberStyle="Integer" 
               ShowButtonSpinner="False"
               local:NumericInputHelper.IsNumericOnly="True" />

这样输入过程中会自动过滤非数字字符,无需等到失去焦点才验证,且所有需要数字输入的控件都能复用这套逻辑。

方法2:自定义数字输入控件

如果需要更定制化的功能,可以直接继承TextBox实现专属数字输入框:

using Avalonia.Controls;
using Avalonia.Input;
using System.Text.RegularExpressions;

public class NumericTextBox : TextBox
{
    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        base.OnTextChanged(e);
        var filteredText = Regex.Replace(Text ?? string.Empty, @"[^0-9]", string.Empty);
        if (filteredText != Text)
        {
            var caretIndex = CaretIndex;
            Text = filteredText;
            CaretIndex = Math.Min(caretIndex, filteredText.Length);
        }
    }

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        base.OnPreviewKeyDown(e);
        if (e.Key is Key.Decimal or Key.Subtract or Key.Add)
        {
            e.Handled = true;
        }
    }
}

然后在XAML中直接使用:

<local:NumericTextBox Text="{Binding Samples, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

补充:绑定整数属性的注意点

如果ViewModel中的属性是int类型,建议绑定加上UpdateSourceTrigger=PropertyChanged,实现输入时实时更新绑定值,还能在属性setter中做额外验证:

private int _samples;
public int Samples
{
    get => _samples;
    set
    {
        // 示例:只允许非负整数
        if (value >= 0)
        {
            _samples = value;
            OnPropertyChanged();
        }
    }
}

内容的提问来源于stack exchange,提问作者Frederik Steinmetz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 16:33:14