WPF附加属性控制TextBox的输入为金额格式

    工作中时长会遇到金额的输入框,网上有很多方案,其中很多采用自定义控件继承TextBox类,扩展校验。此处给出通过附加属性控制TextBox输入格式为金额的solution。

    简单说下原理:

    1.通过附加属性类自定义IsDecimal附加属性设置为True时回调函数。

    2.在回调函数中获取该TextBox实例,并在TextChanged事件增加对该Text校验(校验方式很多,我采用的正则式匹配校验),若符合,通过。否则,将值设为最后一次符合校验的值。

    这里有两个细节:

    ①关于存储上次的符合校验的值,我使用了一个Dictionary<TextBox,String>来存储。在上面的原理“1”中将实例加入到Dictionary中,并默认初始为String.Empty,若字典中已存在该实例则跳过。

    ②在原理“2”中,还需要对光标位置记录,若通过校验,需要更新Dictionary中该TextBox的值。若不通过,除了改为Dictionary中存储的上次值外,还需要将光标位置还原。【改善用户体验】

    下面上代码:

    /// <summary>
    /// ID:Decimal附加属性,针对TextBox
    /// Describe:附加属性控制TextBox仅输入金额,不可为负。小数点前最多14位,后最多两位
    /// 注意:当使用Binding时,若StringFormat和UpdateSourceTrigger=PropertyChanged同时存在,则会出现系统导致的bug,如9.2111111...
    /// Author:ybx
    /// Date:2016-11-2 11:00:15
    /// </summary>
    class DecimalHelper
    {
        private static Dictionary<TextBox, string> _lastValueDictionary = new Dictionary<TextBox, string>();
        private static string reg = @"^[1-9][0-9]{0,13}\.?[0-9]{0,2}$|^[0-9]?\.[0-9]{0,2}$|^$|^[0-9]$";

        public static bool GetIsDecimal(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsDecimalProperty);
        }

        public static void SetIsDecimal(DependencyObject obj, bool value)
        {
            obj.SetValue(IsDecimalProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsDecimal.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsDecimalProperty =
            DependencyProperty.RegisterAttached("IsDecimal", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(false, new PropertyChangedCallback(IsDecimalChanged)));

        private static void IsDecimalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TextBox tb = d as TextBox;
            if (!_lastValueDictionary.Keys.Contains(tb))
            {
                _lastValueDictionary.Add(tb, string.Empty);
            }

            tb.TextChanged -= DecimalCheck;
            if ((bool)e.NewValue)
            {
                tb.TextChanged += DecimalCheck;
            }
        }

        private static void DecimalCheck(object sender, TextChangedEventArgs e)
        {
            var txt = (sender as TextBox);
            int index = txt.SelectionStart;
            if (!new Regex(reg).IsMatch(txt.Text))
            {
                txt.Text = _lastValueDictionary[txt];
                if (index - 1 >= 0)
                    txt.SelectionStart = index - 1;
            }
            else
            {
                _lastValueDictionary[txt] = txt.Text;
            }
        }
    }


    注意:

    当使用Binding时,若StringFormat和UpdateSourceTrigger=PropertyChanged同时存在,则会出现系统导致的bug,如9.2111111...

例如

       

<Window x:Class="DecimalTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:txt="clr-namespace:DecimalTest"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox txt:DecimalHelper.IsDecimal="true" Text="{Binding Num,StringFormat={}{0:f},UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>
此时由于系统机制,输入9.222222时,获取的TextBox的Text会被StringFormat格式为9.22,导致无法正确校验格式。暂时没有更好的方案。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值