Tuesday, October 28, 2014

Xamarin.Forms: Chainable and Strongly-Typed Binding Extension

In Xamarin.Forms, sometimes I like to create my bindings inline with the creation of my controls, as opposed to creating the controls, storing them, then set all bindings at the bottom. So here's an extension method, that adds chaining.

public static class BindableObjectExtensions
{
    // chainable, with a string for property
    // usage : new Button().WithBinding(Button.CommandProperty, "SomeCommand"),
    public static T WithBinding<T>(this T obj, 
        BindableProperty bindableProperty, 
        string path, 
        BindingMode mode = BindingMode.Default, 
        IValueConverter converter = null, 
        object converterParameter = null, 
        string stringFormat = null
    )
        where T:BindableObject
    {
        obj.SetBinding (bindableProperty, new Binding (path, mode, converter, converterParameter, stringFormat));
        return obj;
    }

    // chainable, with a lambda for property
    // usage : new Button().WithBinding(Button.CommandProperty, (MyViewModel vm) => vm.SomeCommand),
    public static TOUT WithBinding<TOUT, TVM, TO>(this TOUT obj, 
        BindableProperty bindableProperty, 
        Expression<Func<TVM, TO>> sourceProperty, 
        BindingMode mode = BindingMode.Default, 
        IValueConverter converter = null, 
        object converterParameter = null, 
        string stringFormat = null
    )
        where TOUT:BindableObject
        where TVM:INotifyPropertyChanged
    {
        obj.SetBinding (bindableProperty, new Binding (((MemberExpression)sourceProperty.Body).Member.Name, mode, converter, converterParameter, stringFormat));
        return obj;
    }
}

Usage :

new StackLayout{
    Children = 
    {
        new Button().WithBinding(Button.CommandProperty, (MyViewModel vm) => vm.SomeCommand),
    },
}

1 comment:

Benoit Jadinon said...


a hacky way to make it support ViewModels in ViewModels :

var body = sourceProperty.Body.ToString ();
string name;
if (body.Contains ("."))
name = body.Substring (body.IndexOf (".", StringComparison.Ordinal) + 1);
else
name = body;

obj.SetBinding (bindableProperty, new Binding (name, mode, converter, converterParameter, stringFormat));