MvvmCross Android转换器导致光标跳转

时间:2016-11-01 12:28:05

标签: c# android xamarin mvvmcross

我们在与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

1 个答案:

答案 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