Reputation: 2210
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
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
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
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