我们在与Android中的EditText控件连接时MvvmCross中的转换器出现问题:
在我们的应用中,用户插入用户数据。我们必须在转换器中对这些数据进行一些计算,然后在viewmodel中写入数据。
只要用户没有还原他的条目,这就有效。 这意味着,如果他使用后退键,则正确编辑该值,直到他达到“。”之前的最后一个小数。 (例如:55.99,当他达到“55.9”时)。 “.9”将被正确删除,但是curosor会跳过剩下的“55”。 我们如何解决这种恼人的行为?
Viewmodel提取:
private Nullable mdValue1 = null;
public Nullable<decimal> Value1
{
get { return mdValue1; }
set
{
SetProperty(ref mdValue1, value);
}
}
private Nullable<decimal> mdValue2;
public Nullable<decimal> Value2
{
get { return mdValue2; }
set
{
SetProperty(ref mdValue2, value, nameof(Value2));
}
}
转换器(简化):
public class DecimalToStringValueConverter : MvxValueConverter<Nullable<decimal>, string>
{
protected override string Convert(Nullable<decimal> poValue, Type poTargetType, object poParameter, CultureInfo poCulture)
{
if (!poValue.HasValue)
{
return null;
}
return poValue.Value.ToString();
}
protected override Nullable<decimal> ConvertBack(string value, Type targetType, object parameter, CultureInfo culture)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
return decimal.Parse(value);
}
}
配置
Android版:4.4 / 5.1 / 7
平台:Xamarin
答案 0 :(得分:2)
似乎发生的事情是当点被移除并转换为小数时,ViewModel中值的结果变化与EditText不同,导致ViewModel设置EditText的值。 / p>
示例: 用户输入59.9
,然后输入退格9
。这会将EditText中的值保留为59.
,并将其作为小数解析为59
到ViewModel。由于59.
不等于59
,ViewModel会将EditText中的值更新为59
,这是导致光标跳转到开头的原因。
解决此问题的一种快速方法是创建一个自定义绑定,以确保在删除最后一个小数位时光标始终位于EditText的末尾。这可以使用SetSelection
来完成,SetValueImpl
将光标定位在public class DecimalEditTextTargetBinding : MvxConvertingTargetBinding
{
protected EditText EditTextControl => Target as EditText;
private IDisposable _subscription;
public DecimalEditTextTargetBinding(EditText target) : base(target)
{
if (target == null)
MvxBindingTrace.Error($"Error - EditText is null in {nameof(DecimalEditTextTargetBinding)}");
}
public override Type TargetType => typeof(string);
public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;
protected override void SetValueImpl(object target, object value)
{
((TextView)target).Text = (string)value;
EditTextControl.SetSelection(EditTextControl.Text?.Length ?? 0);
}
public override void SubscribeToEvents()
{
if (EditTextControl == null)
return;
_subscription = EditTextControl.WeakSubscribe<TextView, AfterTextChangedEventArgs>(
nameof(EditTextControl.AfterTextChanged),
EditTextOnAfterTextChanged);
}
private void EditTextOnAfterTextChanged(object sender, AfterTextChangedEventArgs e)
{
FireValueChanged(EditTextControl.Text);
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_subscription?.Dispose();
_subscription = null;
}
base.Dispose(isDisposing);
}
}
方法中。
Setup.cs
然后在protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
base.FillTargetFactories(registry);
registry.RegisterCustomBindingFactory<EditText>("DecimalText", inputField => new DecimalEditTextTargetBinding(inputField));
}
:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal|numberSigned"
local:MvxBind="DecimalText DecimalToString(Value1)" />
XML用法:
public class DecimalEditTextTargetBinding : MvxConvertingTargetBinding
{
private bool _subscribed;
public DecimalEditTextTargetBinding(EditText target) : base(target)
{
if (target == null)
MvxBindingTrace.Error($"Error - EditText is null in {nameof(DecimalEditTextTargetBinding)}");
}
protected EditText EditTextControl => Target as EditText;
public override Type TargetType => typeof(string);
public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;
protected override void SetValueImpl(object target, object value)
{
((TextView)target).Text = (string)value;
EditTextControl.SetSelection(EditTextControl.Text?.Length ?? 0);
}
public override void SubscribeToEvents()
{
if (EditTextControl == null)
return;
EditTextControl.AfterTextChanged += EditTextOnAfterTextChanged;
_subscribed = true;
}
private void EditTextOnAfterTextChanged(object sender, AfterTextChangedEventArgs e)
{
FireValueChanged(EditTextControl.Text);
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing && EditTextControl != null && _subscribed)
{
EditTextControl.AfterTextChanged -= EditTextOnAfterTextChanged;
_subscribed = false;
}
base.Dispose(isDisposing);
}
}
前MvvmCross 4.4.0的绑定示例:
execute