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); } }
快速使用步骤
- 注册自定义绑定:在你的MvvmCross Setup类中添加绑定注册:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry) { base.FillTargetFactories(registry); registry.RegisterFactory(new MvxCustomBindingFactory<EditText>("FocusText", editText => new MvxEditTextFocusBinding(editText))); }
- 替换布局绑定:在DialogFragment的布局XML里,把原来的
Text绑定换成FocusText:
<EditText android:id="@+id/et_decimal_input" android:inputType="numberDecimal" local:MvxBind="FocusText YourViewModelDecimalProperty" />
这样设置后,用户输入时(输入框获焦)可以自由敲数字和小数点,不会被实时格式化打断;当用户点击其他区域或关闭对话框(输入框失焦)时,数值会自动格式化为指定格式,同时同步到ViewModel的对应属性,彻底解决输入错位的问题。
内容的提问来源于stack exchange,提问作者Jim Wilcox
相关产品推荐
相关产品推荐

