MvvmCross two-way binding "just works" for any control which provides a property API which follows a "Changed" pattern like:
public PType MyProperty { get; set; }
public event EventHandler MyPropertyChanged;
For controls which don't follow this convention or which use a specialised EventHandler, you either have to:
1. Inherit from the control and provide the pattern in the inherited control class
public class ExtraThing : Thing
{
public ExtraThing(Context c, IAttributeSet attrs)
: base(c, attrs)
{
}
protected override SomethingChanged()
{
MyPropertyChanged.Raise(this);
}
public PType MyProperty
{
get { return base.Something(); }
set { base.ChangeSomething(value); }
}
public event EventHandler MyPropertyChanged;
}
2. Or provide a custom target binding
This is discussed in full in http://slodge.blogspot.co.uk/2013/06/n28-custom-bindings-n1-days-of-mvvmcross.html
The code basically required is for a custom 'target binding' which knows how to get/set the property and how to observe its changes:
public class ThingMyPropertyTargetBinding : MvxAndroidTargetBinding
{
protected Thing Thing
{
get { return (Thing) Target; }
}
public ThingMyPropertyTargetBinding (Thing target) : base(target)
{
}
public override void SubscribeToEvents()
{
Thing.MyPropertyChanged += TargetOnMyPropertyChanged;
}
private void TargetOnMyPropertyChanged(object sender, SpecialEventArgs eventArgs)
{
var target = Target as Thing;
if (target == null)
return;
var value = target.GetMyProperty();
FireValueChanged(value);
}
protected override void SetValueImpl(object target, object value)
{
var binaryEdit = (Thing)target;
binaryEdit.SetMyProperty((PType)value);
}
public override Type TargetType
{
get { return typeof(PType); }
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
var target = Target as BinaryEdit;
if (target != null)
{
target.MyPropertyChanged -= TargetOnMyPropertyChanged;
}
}
base.Dispose(isDisposing);
}
}
This "TargetBinding" can then be registered during setup time using code like:
protected override void FillTargetFactories(Cirrious.MvvmCross.Binding.Bindings.Target.Construction.IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterCustomBindingFactory<Thing>(
"SpecialBinding",
thing => new ThingMyPropertyTargetBinding (thing) );
base.FillTargetFactories(registry);
}
For RatingBar
, I think either of these approaches would work ... and I think it would also be useful to get back into the core project for others to use.