Xamarin Forms 1.3 Behavior Binding Bug

In my last post I introduced some of the new features in Xamarin Forms 1.3. I have been playing with the new Bahavior class 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.

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

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);

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

        _stackLayout = bindable;
    }

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

I have posted this as a bug on the Xamarin Forms forums here

5 thoughts on “Xamarin Forms 1.3 Behavior Binding Bug

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s