如何让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
相关产品推荐
相关产品推荐

