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

WPF如何在代码后置中设置原生TextBox可接受的小数位数

WPF原生TextBox限制小数位数的实现方法

WPF原生TextBox没有内置的Mask属性,不过可以通过以下两种简便方式实现2位/3位小数的输入限制,适配代码后置的调用需求:

方法1:封装通用小数限制附加属性(推荐,批量场景更易用)

可以先在项目里新增一个静态辅助类,封装附加属性,后续任意TextBox都可以在代码后置直接调用设置位数:

public static class TextBoxDecimalExtension
{
    // 注册附加属性:允许的小数位数,-1表示不限制
    public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.RegisterAttached(
        "DecimalPlaces", typeof(int), typeof(TextBoxDecimalExtension), new PropertyMetadata(-1, OnDecimalPlacesChanged));

    public static int GetDecimalPlaces(DependencyObject obj)
    {
        return (int)obj.GetValue(DecimalPlacesProperty);
    }

    public static void SetDecimalPlaces(DependencyObject obj, int value)
    {
        obj.SetValue(DecimalPlacesProperty, value);
    }

    private static void OnDecimalPlacesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not TextBox textBox) return;
        textBox.PreviewTextInput -= TextBox_PreviewTextInput;
        textBox.PreviewKeyDown -= TextBox_PreviewKeyDown;
        DataObject.RemovePastingHandler(textBox, OnPaste);

        var places = (int)e.NewValue;
        if (places < 0) return;

        textBox.PreviewTextInput += TextBox_PreviewTextInput;
        textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
        DataObject.AddPastingHandler(textBox, OnPaste);
    }

    private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        var textBox = (TextBox)sender;
        var places = GetDecimalPlaces(textBox);
        var fullText = textBox.Text.Insert(textBox.SelectionStart, e.Text);
        e.Handled = !IsValidDecimal(fullText, places);
    }

    private static void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        // 禁用空格输入
        if (e.Key == Key.Space) e.Handled = true;
    }

    private static void OnPaste(object sender, DataObjectPastingEventArgs e)
    {
        if (!e.DataObject.GetDataPresent(typeof(string)))
        {
            e.CancelCommand();
            return;
        }
        var pasteText = e.DataObject.GetData(typeof(string)) as string;
        var textBox = (TextBox)sender;
        var places = GetDecimalPlaces(textBox);
        var fullText = textBox.Text.Insert(textBox.SelectionStart, pasteText);
        if (!IsValidDecimal(fullText, places)) e.CancelCommand();
    }

    // 校验小数格式
    private static bool IsValidDecimal(string input, int decimalPlaces)
    {
        // 匹配规则:可选负号,整数部分数字,可选小数点加最多decimalPlaces位小数
        var regex = new Regex($"^-?\\d*(\\.\\d{{0,{decimalPlaces}}})?$");
        return regex.IsMatch(input);
    }
}

在代码后置中调用方式和你之前用Infragistics的方式几乎一致:

// 设置允许3位小数
TextBoxDecimalExtension.SetDecimalPlaces(txtInvoiceAmount, 3);
// 设置允许2位小数
TextBoxDecimalExtension.SetDecimalPlaces(txtInvoiceAmount, 2);

方法2:单文本框直接加事件处理(临时小量场景适用)

如果只有少量TextBox需要限制,也可以直接在代码后置写事件:

// 窗口初始化时绑定事件
txtInvoiceAmount.PreviewTextInput += (s,e) => 
{
    var fullText = txtInvoiceAmount.Text.Insert(txtInvoiceAmount.SelectionStart, e.Text);
    // 2位小数就把{0,3}改成{0,2}即可
    e.Handled = !Regex.IsMatch(fullText, @"^-?\d*(\.\d{0,3})?$");
};
// 额外补充粘贴拦截和空格禁用逻辑即可

两种方式都支持负数、整数输入,同时拦截非法输入和粘贴的非法内容,完全覆盖你之前的Mask功能需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:36:03