문제

I've been converting an existing application over to use MvvmCross (HotTuna) and one of the Android controls I've used a fair bit is the RatingBar.

I'm having trouble getting 2-way binding working on this control and I suspect that I should implement an MvxRatingBar in a similar style to the other Android controls under Cirrious.MvvmCross.Binding.Droid.Views.

Currently using just standard binding I have the following code:

    <RatingBar
    style="@style/scoreRatingBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:isIndicator="false"
    android:paddingTop="5dp"
    local:MvxBind="Max OutOf; NumStars OutOf; Rating ScoreA, Mode=TwoWay" />

My question is, would this be the recommended way to solve the problem of two-way binding on a control such as RatingBar?

도움이 되었습니까?

해결책

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.

다른 팁

Just for reference, Rating target binding is built in newer versions of Mvx as you can see here: List of local:MvxBind binders

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top