Andres Talavera
Andres Talavera

Reputation: 2210

MvvmCross : Empty binding target passed to MvxTargetBindingFactoryRegistry

I created an Android application with Xamarin and MvvmCross. I want to bind some views (text, editing text, button) to my ViewModel. Nothing strange well so far. But my bindings don’t apply… When I use typed FindViewById, I don’t get the traced error but bindings doesn’t apply.

When I run the application, I have the following trace:

MvxBind:Error: Empty binding target passed to MvxTargetBindingFactoryRegistry
MvxBind:Warning: Failed to create target binding for binding for TextProperty

My override of OnCreate(Bundle bundle) void is :

SetContentView(Resource.Layout.Reference);
var referenceTextView = FindViewById(Resource.Id.referenceEditView); // untyped FindViewById
var siteTextView = FindViewById<TextView>(Resource.Id.siteTextView); // typed FindViewById<T>
//var goButton = FindViewById<Button>(Resource.Id.goButton);
var bindingsSet = this.CreateBindingSet<ReferenceView, ReferenceViewModel>();
bindingsSet.Bind(referenceTextView).To(vm => vm.Reference).Mode(MvxBindingMode.TwoWay);
bindingsSet.Bind(siteTextView).To(vm => vm.Site);
//bindingsSet.Bind(goButton).To(vm => vm.GoCommand);
bindingsSet.Apply();
base.OnCreate(bundle);

I’ve tried to do in the AXML :

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/siteTextView"
    android:text="####"
    local:MvxBind="Text Site"
    android:gravity="center" />
<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/referenceTextView"
    android:hint="Numéro de dossier"
    local:MvxBind="Text Reference" />
<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Accéder"
    android:id="@+id/goButton"
    local:MvxBind="Click GoCommand" />

The getters and setters of my properties use RaiseAndSetIfChanged method :

private string _reference;
public string Reference
{
    get { return _reference; }
    set { this.RaiseAndSetIfChanged(ref _reference, value, () => Reference); }
}

I’ve the same LinkerPleaseInclude class than LinkerPleaseInclude original class. My setup inherits from MvxAndroidSetup class And on other ViewModels, the bindings are applied correctly.

Upvotes: 0

Views: 640

Answers (3)

Cheesebaron
Cheesebaron

Reputation: 24470

You need to call base.OnCreate(bundle); before SetContentView as the ViewModel is located and attached inside of that call. Failing to do so will obviously give you the exact errors you see. Source will be null and will not bind to the target.

So you can either do:

base.OnCreate(bundle);
SetContentView(Resource.Layout.Reference);

And have all your bindings in your AXML. Or you can do the other approach setting the bindings behind the scenes:

base.OnCreate(bundle);
SetContentView(Resource.Layout.Reference);

var referenceTextView = FindViewById<TextView>(Resource.Id.referenceEditView);
var siteTextView = FindViewById<TextView>(Resource.Id.siteTextView);

var bset = this.CreateBindingSet<ReferenceView, ReferenceViewModel>();
bset.Bind(referenceTextView).To(vm => vm.Reference);
bset.Bind(siteTextView).To(vm => vm.Site);
bset.Apply();

Just make sure to call base.OnCreate to begin with.

Upvotes: 1

Sven-Michael St&#252;be
Sven-Michael St&#252;be

Reputation: 14760

The warnings

MvxBind:Error: 2,20 Empty binding target passed to MvxTargetBindingFactoryRegistry MvxBind:Warning: 2,20 Failed to create target binding for binding for Text

are caused by var referenceTextView = FindViewById(Resource.Id.referenceEditView); resulting in referenceTextView to be of type View.

MvvmCross is searching for the default binding target property of the type TTarget when calling Bind<TTArget> without For(targetProperty). This is just a look up in a table like:

TTarget       Property
----------------------
TextView      Text
Button        Click
...           ...  

In your case TTarget is View instead of TextView, because you pass it into bindingsSet.Bind(referenceTextView) wich is the implicit call of bindings.Bind<View>(btnNumber). View has no default binding target property. You have to set it explicitly like

bindings.Bind(btnNumber).For("Text")

or use the typed FindViewById<TextView>.

Upvotes: 1

Iain Smith
Iain Smith

Reputation: 9703

I dont think you need to bind twice, remove these lines:

var referenceTextView = FindViewById(Resource.Id.referenceEditView); // untyped FindViewById
var siteTextView = FindViewById<TextView>(Resource.Id.siteTextView); // typed FindViewById<T>
//var goButton = FindViewById<Button>(Resource.Id.goButton);
var bindingsSet = this.CreateBindingSet<ReferenceView, ReferenceViewModel>();
bindingsSet.Bind(referenceTextView).To(vm => vm.Reference).Mode(MvxBindingMode.TwoWay);
bindingsSet.Bind(siteTextView).To(vm => vm.Site);
//bindingsSet.Bind(goButton).To(vm => vm.GoCommand);
bindingsSet.Apply();

So your on create is just this:

SetContentView(Resource.Layout.Reference);
base.OnCreate(bundle);

And keep the bindings in the axml file.

Make sure you have this at the top of your xaml file:

xmlns:local="http://schemas.android.com/apk/res-auto"

Also if you are doing bindings in the cs file, the MvvmCross binding mode is TwoWay by default. So you dont need .Mode(MvxBindingMode.TwoWay);

Upvotes: 0

Related Questions