Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 75885

Xamarin Forms 1.3 Behavior Binding Bug

$
0
0

I have been playing with the new Bahavior class in 1.3 and discovered a bug when using Binding on a BindableProperty. I created the following behavior to allow an ItemsSource and an ItemTemplate to be attached to a StackLayout.

public class ItemsSourceBehavior : Behavior<StackLayout>
{
    private StackLayout _stackLayout;

    public static readonly BindableProperty ItemsSourceProperty = 
        BindableProperty.Create<ItemsSourceBehavior, IEnumerable>(p => p.ItemsSource, null, BindingMode.Default, null, ItemsSourceChanged);

    public IEnumerable ItemsSource
    { 
        get { return (IEnumerable)GetValue(ItemsSourceProperty); } 
        set { SetValue(ItemsSourceProperty, value); } 
    }

    public static readonly BindableProperty ItemTemplateProperty = 
        BindableProperty.Create<ItemsSourceBehavior, DataTemplate>(p => p.ItemTemplate, null);

    public DataTemplate ItemTemplate
    { 
        get { return (DataTemplate)GetValue(ItemTemplateProperty); } 
        set { SetValue(ItemTemplateProperty, value); } 
    }

    private static void ItemsSourceChanged(BindableObject bindable, IEnumerable oldValue, IEnumerable newValue)
    {
        var behavior = bindable as ItemsSourceBehavior;
        behavior.SetItems();
    }

    private void SetItems()
    {
        _stackLayout.Children.Clear();

        if (ItemsSource == null)
            return;

        foreach (var item in ItemsSource)
            _stackLayout.Children.Add(GetItemView(item));
    }

    private View GetItemView(object item)
    {
        var content = ItemTemplate.CreateContent();
        var view = content as View;
        view.BindingContext = item;
        return view;
    }

    protected override void OnAttachedTo(StackLayout bindable)
    {
        base.OnAttachedTo(bindable);
        _stackLayout = bindable;
    }
}

However the BindableProperties never get set when using a Binding expression in Xaml like this.

                <ScrollView Orientation="Horizontal">
                    <StackLayout Orientation="Horizontal">
                        <StackLayout.Behaviors>
                            <behaviors:ItemsSourceBehavior ItemsSource="{Binding WeatherPeriods}" ItemTemplate="{StaticResource itemItemplate}" />
                        </StackLayout.Behaviors>
                    </StackLayout>
                </ScrollView>

Notice here that ItemsSource uses a Binding expression and ItemTemplate uses a DataTemplate as a StaticResource. The ItemTemplate does get set but the ItemSource does not. I discovered that the BindingContext on the Behavior never gets set and therefore the ItemsSource is unable to evaluate the BindingExpression. A workaround for this is to set the BindingContext of the Behavior to the BindingContext of the StackLayout when its BindingContext changes like this:

    protected override void OnAttachedTo(StackLayout bindable)
    {
        base.OnAttachedTo(bindable);
        _stackLayout = bindable;

        bindable.BindingContextChanged += (sender, e) =>
            BindingContext = _stackLayout.BindingContext;
    }

Now ItemsSourceChanged gets called as a result of the BindingContext being set.

Please let me know if there is a better solution to this.


Viewing all articles
Browse latest Browse all 75885

Trending Articles