2
votes

In Silverlight (and other XAML based technologies) there is a method called GetBindingExpression which allows us to check what binding there is on a given dependency property. The method is on FrameworkElement so every single control gives us access to the binding expression.

For example:

var selectedItemBindingExpression = GetBindingExpression(SelectedItemProperty);

But, there doesn't seem to be an equivalent in Xamarin Forms. Is there a way to get a binding expression from a BindableProperty property in Xamarin Forms?

2

2 Answers

11
votes

I don't believe there are any public APIs available in Xamarin.Forms to access to the BindingExpression - but you can use reflection to access the associated Binding and thus the BindingExpression

public static class BindingObjectExtensions
{
    public static Binding GetBinding(this BindableObject self, BindableProperty property)
    {
        var methodInfo = typeof(BindableObject).GetTypeInfo().GetDeclaredMethod("GetContext");
        var context = methodInfo?.Invoke(self, new[] { property });

        var propertyInfo = context?.GetType().GetTypeInfo().GetDeclaredField("Binding");
        return propertyInfo?.GetValue(context) as Binding;
    }

    public static object GetBindingExpression(this Binding self)
    {
        var fieldInfo = self?.GetType().GetTypeInfo().GetDeclaredField("_expression");
        return fieldInfo?.GetValue(self);
    }
}

Sample usage - Get binding-expression

var expr = this.GetBinding(TextProperty).GetBindingExpression();

Sample usage - Get binding path (update 07/27)

//to access path - you can directly use the binding object
var binding = this.GetBinding(TextProperty);
var path = binding?.Path;
1
votes

Improved Sharada Gururaj's solution:

public static class BindingObjectExtensions
{
    private static MethodInfo _bindablePropertyGetContextMethodInfo = typeof(BindableObject).GetMethod("GetContext", BindingFlags.NonPublic | BindingFlags.Instance);
    private static FieldInfo _bindablePropertyContextBindingFieldInfo;

    public static Binding GetBinding(this BindableObject bindableObject, BindableProperty bindableProperty)
    {
        object bindablePropertyContext = _bindablePropertyGetContextMethodInfo.Invoke(bindableObject, new[] { bindableProperty });

        if (bindablePropertyContext != null)
        {
            FieldInfo propertyInfo = _bindablePropertyContextBindingFieldInfo = 
                _bindablePropertyContextBindingFieldInfo ?? 
                    bindablePropertyContext.GetType().GetField("Binding");

            return (Binding) propertyInfo.GetValue(bindablePropertyContext);
        }

        return null; 
}

My solution has following improvements:

  1. Caching of objects obtained by reflection (improves performance)
  2. Removed unnecessary null checks
  3. Use of reflection directly, the use of IntrospectionExtensions is unnecessary
  4. GetBindingExpression method is not needed (all information about the binding can be retrieved from the Binding class)