MvxValueConverter 打破绑定

MvxValueConverter breaks bindings

当我将存根转换器应用到 TextView 时,它以某种方式破坏了绑定

这是带有绑定的 TextView

<EditText
    android:id="@+id/etAutoNumber"
    android:layout_width="fill_parent"
    android:textSize="34sp"
    android:capitalize="characters"
    android:hint="50 АА 101101"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:layout_marginTop="16dp"
    android:layout_height="wrap_content"
    android:textColor="@color/primary_text"
    android:maxLength="12"
    local:MvxBind="Text DocumentFormatter(Number)"
    android:imeOptions="actionGo"
    android:inputType="textPostalAddress" />

这里是转换器应用:local:MvxBind="Text DocumentFormatter(Number)"

这是转换器,它基本上什么都不做,它位于.Droid Project

public class DocumentFormatterValueConverter : MvxValueConverter
{
    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Mvx.Trace("convert for {0}", value);
        return base.Convert(value, targetType, parameter, culture);
    }
}

如果我重写 ConvertBack,我将从 TextView 接收到 Converter 的新字符串,但仍然缺少绑定。

这是 viewModel 属性:

 public string Number
        {
            get { return _number; }
            set
            {
                _number = value;
                RaisePropertyChanged(() => Number);
                // some additional work
                // ...
            }
        }

如果我用 local:MvxBind="Text Number" 替换绑定它工作正常,如果我使用转换器 - 它工作一次:我在 Init 中设置 Number=String.Empty 并且它调用一次转换器

这是从 Init 到 GoCommand 的输出日志

mvx:Diagnostic:  5,24 TrackerService.LogEvent Init.ViewAuto
01-07 16:18:48.844 I/mono-stdout( 2442): mvx:Diagnostic:  5,24 TrackerService.LogEvent Init.ViewAuto
[0:] mvx:Diagnostic:  5,24 TrackerService.LogEvent Init.ViewAuto
[0:] 
MvxBind:Error:  5,40 View type not found - android.support.v7.widget.Toolbar
01-07 16:18:49.025 I/mono-stdout( 2442): MvxBind:Error:  5,40 View type not found - android.support.v7.widget.Toolbar
[0:] MvxBind:Error:  5,40 View type not found - android.support.v7.widget.Toolbar
01-07 16:18:49.121 D/Mono    ( 2442): Assembly Ref addref Cirrious.MvvmCross.Binding[0xac371880] -> System.Threading[0xac3fe340]: 7
01-07 16:18:49.146 D/Mono    ( 2442): Assembly Ref addref Cirrious.CrossCore[0xac3718e0] -> System.ObjectModel[0x9f6a1760]: 5
01-07 16:18:49.153 D/Mono    ( 2442): Assembly Ref addref Cirrious.MvvmCross[0xac371b20] -> System.Threading[0xac3fe340]: 8
[0:] 
mvx:Diagnostic:  5,56 convert for 
[0:] mvx:Diagnostic:  5,56 convert for 
01-07 16:18:49.169 I/mono-stdout( 2442): mvx:Diagnostic:  5,56 convert for 
Resolved pending breakpoint at 'c:\Users\...\EnterFirstAutoViewModel.cs:23,1' to void EnterFirstAutoViewModel.<DoGoCommand>d__0.MoveNext () [0x0001e].
01-07 16:19:03.837 D/Mono    ( 2442): Assembly Ref addref Fines.Core[0x9f63b1c0] -> System.Diagnostics.Debug[0x9f63bc40]: 2
01-07 16:19:03.837 D/Mono    ( 2442): Assembly Ref addref System.Diagnostics.Debug[0x9f63bc40] -> mscorlib[0xac3714c0]: 30
01-07 16:19:14.032 D/Mono    ( 2442): Assembly Ref addref Chance.MvvmCross.Plugins.UserInteraction.Droid[0xac3715e0] -> Cirrious.CrossCore.Droid[0xac371820]: 6

我设法在 4.0.4 设备上获得了更详细的输出

mvx:Diagnostic:211,37 TrackerService.LogEvent Init.ViewAuto
[0:] mvx:Diagnostic:211,37 TrackerService.LogEvent Init.ViewAuto
01-07 16:39:24.929 I/mono-stdout( 3848): mvx:Diagnostic:211,37 TrackerService.LogEvent Init.ViewAuto
01-07 16:39:24.947 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.widget.TextView$ChangeWatcher@418ffd38: 
01-07 16:39:24.947 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.TextKeyListener@41c5cbb8: 
01-07 16:39:24.947 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.SingleLineTransformationMethod@41768658: 
01-07 16:39:24.947 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.Selection$START@40e51018: 
01-07 16:39:24.948 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.Selection$END@40e5df70: 
01-07 16:39:24.948 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.widget.TextView$ChangeWatcher@418ffd38: 
01-07 16:39:24.948 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.TextKeyListener@41c5cbb8: 
01-07 16:39:24.949 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.SingleLineTransformationMethod@41768658: 
01-07 16:39:24.949 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.Selection$START@40e51018: 
01-07 16:39:24.949 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.Selection$END@40e5df70: 
[0:] 
mvx:Diagnostic:211,91 convert for: .
[0:] mvx:Diagnostic:211,91 convert for: .
01-07 16:39:25.469 I/mono-stdout( 3848): mvx:Diagnostic:211,91 convert for: .
01-07 16:39:25.474 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.widget.TextView$ChangeWatcher@418ffd38: 
01-07 16:39:25.474 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.TextKeyListener@41c5cbb8: 
01-07 16:39:25.474 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.SingleLineTransformationMethod@41768658: 
01-07 16:39:25.475 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.Selection$START@40e51018: 
01-07 16:39:25.475 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.Selection$END@40e5df70: 
01-07 16:39:25.489 D/ActivityThread( 3848): ACT-AM_ON_RESUME_CALLED ActivityRecord{418fb640 token=android.os.BinderProxy@418fae28 {...app/...droid.views.EnterFirstAutoView}}
01-07 16:39:25.492 D/ActivityThread( 3848): ACT-LAUNCH_ACTIVITY handled : 0 / ActivityRecord{418fb640 token=android.os.BinderProxy@418fae28 {...app/...droid.views.EnterFirstAutoView}}
01-07 16:39:25.494 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.DynamicLayout$ChangeWatcher@41c729f8: 
01-07 16:39:25.525 D/OpenGLRenderer( 3848): Flushing caches (mode 0)
01-07 16:39:25.566 V/TextView( 3848): onSpanRemoved s=0 e=0 what=android.text.DynamicLayout$ChangeWatcher@41c729f8: 
01-07 16:39:25.566 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.DynamicLayout$ChangeWatcher@41c70f70: 
01-07 16:39:25.594 W/IInputConnectionWrapper( 3848): showStatusIcon on inactive InputConnection
01-07 16:39:25.608 D/ActivityThread( 3848): ACT-DESTROY_ACTIVITY handled : 1 / android.os.BinderProxy@418d8258
01-07 16:39:25.612 D/ActivityThread( 3848): ACT-DESTROY_ACTIVITY handled : 1 / android.os.BinderProxy@418f3d98
01-07 16:39:28.261 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.method.Touch$DragState@41d224b8: 
01-07 16:39:28.344 V/TextView( 3848): onSpanRemoved s=0 e=0 what=android.text.method.Touch$DragState@41d224b8: 
01-07 16:39:28.467 V/TextView( 3848): onSpanRemoved s=0 e=0 what=android.text.DynamicLayout$ChangeWatcher@41c70f70: 
01-07 16:39:28.467 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.DynamicLayout$ChangeWatcher@41811cd8: 
01-07 16:39:29.844 V/TextView( 3848): onSpanAdded s=0 e=0 what=android.text.NoCopySpan$Concrete@40eab6c8: 
01-07 16:39:29.844 V/TextView( 3848): beforeTextChanged start=0 before=0 after=1: 
01-07 16:39:29.844 V/TextView( 3848): onTextChanged start=0 before=0 after=1: 1
01-07 16:39:29.844 V/TextView( 3848): afterTextChanged: 1
01-07 16:39:29.845 V/TextView( 3848): onSpanAdded s=0 e=1 what=android.text.NoCopySpan$Concrete@40eee968: 1
01-07 16:39:30.089 V/TextView( 3848): onSpanChanged s=0 e=0 st=1 en=1 what=android.text.NoCopySpan$Concrete@40eab6c8: 1
01-07 16:39:30.090 V/TextView( 3848): beforeTextChanged start=1 before=0 after=1: 1
01-07 16:39:30.090 V/TextView( 3848): onTextChanged start=1 before=0 after=1: 12
01-07 16:39:30.090 V/TextView( 3848): afterTextChanged: 12
01-07 16:39:30.091 V/TextView( 3848): onSpanChanged s=0 e=1 st=1 en=2 what=android.text.NoCopySpan$Concrete@40eee968: 12
01-07 16:39:30.295 V/TextView( 3848): onSpanChanged s=1 e=1 st=2 en=2 what=android.text.NoCopySpan$Concrete@40eab6c8: 12
01-07 16:39:30.295 V/TextView( 3848): beforeTextChanged start=2 before=0 after=1: 12
01-07 16:39:30.296 V/TextView( 3848): onTextChanged start=2 before=0 after=1: 123
01-07 16:39:30.296 V/TextView( 3848): afterTextChanged: 123
01-07 16:39:30.297 V/TextView( 3848): onSpanChanged s=1 e=2 st=2 en=3 what=android.text.NoCopySpan$Concrete@40eee968: 123
01-07 16:39:30.926 V/TextView( 3848): onSpanChanged s=2 e=2 st=3 en=3 what=android.text.NoCopySpan$Concrete@40eab6c8: 123
01-07 16:39:30.926 V/TextView( 3848): beforeTextChanged start=3 before=0 after=1: 123
01-07 16:39:30.926 V/TextView( 3848): onTextChanged start=3 before=0 after=1: 1234
01-07 16:39:30.927 V/TextView( 3848): afterTextChanged: 1234
01-07 16:39:30.927 V/TextView( 3848): onSpanChanged s=2 e=3 st=3 en=4 what=android.text.NoCopySpan$Concrete@40eee968: 1234
01-07 16:39:31.141 V/TextView( 3848): onSpanChanged s=3 e=3 st=4 en=4 what=android.text.NoCopySpan$Concrete@40eab6c8: 1234
01-07 16:39:31.141 V/TextView( 3848): beforeTextChanged start=4 before=0 after=1: 1234
01-07 16:39:31.141 V/TextView( 3848): onTextChanged start=4 before=0 after=1: 12345
01-07 16:39:31.141 V/TextView( 3848): afterTextChanged: 12345
01-07 16:39:31.142 V/TextView( 3848): onSpanChanged s=3 e=4 st=4 en=5 what=android.text.NoCopySpan$Concrete@40eee968: 12345
01-07 16:40:16.717 V/BaseInputConnection( 3848): finishComposingText
01-07 16:40:16.725 V/TextView( 3848): onSpanRemoved s=0 e=5 what=android.text.DynamicLayout$ChangeWatcher@41811cd8: 12345
01-07 16:40:16.725 V/TextView( 3848): onSpanAdded s=0 e=5 what=android.text.DynamicLayout$ChangeWatcher@41cbd000: 12345

我不知道是什么导致了这样的错误,有人能帮我吗?

问题出在 MvxValueConverter 的基本虚方法中

public abstract class MvxValueConverter
    : IMvxValueConverter
{
    public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return MvxBindingConstant.UnsetValue;
    }

    public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return MvxBindingConstant.UnsetValue;
    }
}

如您所见returns MvxBindingConstant.UnsetValue; 因此,当您只需要 Convert 实现时,不要忘记也覆盖 ConvertBack。

public class DocumentFormatterValueConverter : MvxValueConverter<string,string>
{
    protected override string Convert(string value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //return base.Convert(value, targetType, parameter, culture);
        return DocumentFormatter.FormatNumber(value); 
    }

    protected override string ConvertBack(string value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //return base.ConvertBack(value, targetType, parameter, culture);
        return value;
    }
}