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

MvvmCross中MvxDialogFragment绑定decimal到文本框的异常问题

解决MvxDialogFragment小数数值输入时的格式化错位问题

我之前也踩过一模一样的坑——用MvxDialogFragment做带小数位的数值输入框时,直接绑定Text属性会搞崩输入体验:比如想输入10.00,敲完1立刻显示1.00,再敲0就变成01.00,光标还乱跳,完全没法正常输入。

后来靠Stuart早年帮我写的FocusText自定义绑定解决了这个问题,核心思路就是区分输入状态和显示状态:输入框获取焦点时,让用户自由输入不触发格式化;失去焦点时再统一格式化数值并同步到ViewModel,完美避开了实时格式化导致的错位问题。

自定义绑定的完整实现代码

public class MvxEditTextFocusBinding : MvxConvertingTargetBinding
{
    private readonly EditText _editText;
    private bool _hasFocus;
    private object _originalValue;

    public MvxEditTextFocusBinding(EditText editText) : base(editText)
    {
        _editText = editText;
        // 监听焦点变化和文本输入事件
        _editText.FocusChange += EditTextOnFocusChange;
        _editText.TextChanged += EditTextOnTextChanged;
    }

    private void EditTextOnFocusChange(object sender, View.FocusChangeEventArgs e)
    {
        _hasFocus = e.HasFocus;
        if (!_hasFocus)
        {
            // 失去焦点时:格式化数值并同步到绑定源
            if (double.TryParse(_editText.Text, out var inputValue))
            {
                SetValue(inputValue);
                // 按需求格式化显示(这里是保留两位小数)
                _editText.Text = inputValue.ToString("F2");
            }
        }
        else
        {
            // 获取焦点时:显示原始数值,让用户自由输入
            _originalValue = GetValue();
            if (_originalValue is double storedValue)
            {
                _editText.Text = storedValue.ToString();
            }
        }
    }

    private void EditTextOnTextChanged(object sender, Android.Text.TextChangedEventArgs e)
    {
        // 仅在获取焦点时允许自由输入,同时做基础输入校验
        if (_hasFocus)
        {
            var inputText = _editText.Text;
            // 限制:只能有一个小数点,且小数点后最多两位
            if (inputText.Count(c => c == '.') > 1)
            {
                _editText.Text = inputText.Remove(inputText.LastIndexOf('.'), 1);
                _editText.SetSelection(_editText.Text.Length);
            }
            else if (inputText.Contains('.') && inputText.Split('.')[1].Length > 2)
            {
                _editText.Text = inputText.Substring(0, inputText.Length - 1);
                _editText.SetSelection(_editText.Text.Length);
            }
        }
    }

    public override Type TargetType => typeof(double);
    public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;

    protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            _editText.FocusChange -= EditTextOnFocusChange;
            _editText.TextChanged -= EditTextOnTextChanged;
        }
        base.Dispose(isDisposing);
    }
}

快速使用步骤

  1. 注册自定义绑定:在你的MvvmCross Setup类中添加绑定注册:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
    base.FillTargetFactories(registry);
    registry.RegisterFactory(new MvxCustomBindingFactory<EditText>("FocusText", 
        editText => new MvxEditTextFocusBinding(editText)));
}
  1. 替换布局绑定:在DialogFragment的布局XML里,把原来的Text绑定换成FocusText:
<EditText
    android:id="@+id/et_decimal_input"
    android:inputType="numberDecimal"
    local:MvxBind="FocusText YourViewModelDecimalProperty" />

这样设置后,用户输入时(输入框获焦)可以自由敲数字和小数点,不会被实时格式化打断;当用户点击其他区域或关闭对话框(输入框失焦)时,数值会自动格式化为指定格式,同时同步到ViewModel的对应属性,彻底解决输入错位的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:10:53