In this article we'll look at how to create two Behaviors for ListView:

One to allow an order to be associated when one of the items in the list is clicked.

One second to implement the infinite scroll

A small difference with WPF:

Behaviors in Xamarin.Forms are slightly different from their WPF counterparts.

They have no AssociatedObject property. The other major difference is that their DataContext is not initialized like that of a normal view.

To solve these little problems, we're going to define a basic class of our behaviors that will add these two behaviors.


public abstract class BaseBehavior : Behavior<ListView>
where T : BindableObject
{
   public T AssociatedObject { get; private set; }

   protected override void OnAttachedTo(T bindable)
   {
      base.OnAttachedTo(bindable);

      // Lors de la construction on définit la propriété AssociatedObject
      AssociatedObject = bindable;

      //Si le contexte est != NULL on initiliase le contexte de du Behavior avec celui de l'objet courant
      if (bindable.BindingContext != null)
      {
      BindingContext = bindable.BindingContext;
      }

      bindable.BindingContextChanged += OnBindingContextChanged;
   }

   protected override void OnDetachingFrom(T bindable)
   {
      base.OnDetachingFrom(bindable);
      //On se désabonne
      bindable.BindingContextChanged -= OnBindingContextChanged;

      // Lors de la construction on définit la propriété AssociatedObject
      AssociatedObject = null;
   }

   private void OnBindingContextChanged(object sender, EventArgs e)
   {
      OnBindingContextChanged();
   }

   protected override void OnBindingContextChanged()
   {
      base.OnBindingContextChanged();
      BindingContext = AssociatedObject.BindingContext;
   }
}

OnItemTappedBehavior:

In my projects I often want to associate a command with the user click/touch action on a line of my ListView But Xamarin Forms does not provide this mechanism by default.

So I'm going to have to create a Behavior that subscribes to the ItemTapped event and invokes my command.


    public class ListViewOnItemTappedBehavior : BaseBehavior<ListView>
    {
        protected override void OnAttachedTo(ListView bindable)
        {
            base.OnAttachedTo(bindable);
            // Abonnement à ItemTapped
            bindable.ItemTapped += Bindable_ItemTapped;
        }

        protected override void OnDetachingFrom(ListView bindable)
        {
            base.OnDetachingFrom(bindable);
            // Désabonnement à ItemTapped (très important sans ça vous risquez de créer des fuites mémoire).
            bindable.ItemTapped -= Bindable_ItemTapped;
        }

        private void Bindable_ItemTapped(object sender, ItemTappedEventArgs e)
        {
            var cmd = Command;

            if (cmd != null &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; cmd.CanExecute(null))
            {
               cmd.Execute(e.Item);
            }
        }

        public static readonly BindableProperty CommandProperty =
            BindableProperty.CreateAttached(
                nameof(Command),
                typeof(ICommand),
                typeof(ListViewOnItemTappedBehavior),
                null);

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
    }

Then to use it is very simple:


       <ListView.Behaviors>
            <behavior:ListViewOnItemTappedBehavior 
                        Command="{Binding Path=ItemSelectedCommand, Mode=OneWay}" />
        </ListView.Behaviors>

I'm going to tell you something.

In almost all my projects I now need a self-page list.

The idea is that when you get to the end of the list you start loading a new page.

To do this we will need two properties:

Property Command which will be invoked when the list needs to load more items.

Property NumberOfItemsBeforeLoadMore Which will be from which end-list index we will start loading a new page of data.


    public class InfiniteScrollBehavior : BaseBehavior&amp;amp;amp;amp;lt;ListView&amp;amp;amp;amp;gt;
    {
        public static readonly BindableProperty CommandProperty =
            BindableProperty.Create(
                nameof(Command),
                typeof(ICommand),
                typeof(InfiniteScrollBehavior),
                null);

        public ICommand Command
        {
            get
            {
                return (ICommand)GetValue(CommandProperty);
            }
            set
            {
                SetValue(CommandProperty, value);
            }
        }

        public static readonly BindableProperty NumberOfItemsBeforeLoadMoreProperty =
            BindableProperty.Create(
                nameof(NumberOfItemsBeforeLoadMore),
                typeof(uint),
                typeof(InfiniteScrollBehavior),
                1U,
                BindingMode.OneWay);

        public uint NumberOfItemsBeforeLoadMore
        {
            get
            {
                return (uint)GetValue(NumberOfItemsBeforeLoadMoreProperty);
            }
            set
            {
                SetValue(NumberOfItemsBeforeLoadMoreProperty, value);
            }
        }

        protected override void OnAttachedTo(ListView bindable)
        {
            base.OnAttachedTo(bindable);
            bindable.ItemAppearing += InfiniteListView_ItemAppearing;
        }

        protected override void OnDetachingFrom(ListView bindable)
        {
            base.OnDetachingFrom(bindable);
            bindable.ItemAppearing -= InfiniteListView_ItemAppearing;
        }

        private void InfiniteListView_ItemAppearing(object sender, ItemVisibilityEventArgs e)
        {
            var items = AssociatedObject.ItemsSource as IList;
            if (Command != null &&
                items != null &&
                items.IndexOf(e.Item) >= items.Count - NumberOfItemsBeforeLoadMore)
            {
                if (Command.CanExecute(null))
                {
                    Command.Execute(null);
                }
            }
        }
    }

As the behaviour precedes the use is also very simple.

Please note that the property allows you to settle from which item


        <ListView.Behaviors>
            <behavior:ListViewOnItemTappedBehavior 
                        Command="{Binding Path=ItemSelectedCommand, Mode=OneWay}" />
            <behavior:InfiniteScrollBehavior 
                        NumberOfItemsBeforeLoadMore="10"
                        Command="{Binding Path=LoadMoreCommand, Mode=OneWay}" />
        </ListView.Behaviors>

To go further:

I advise you to watch the excellent podcast What 's up with Xamarin.Forms ? or the audio format with Thomas Lebrun as a guest.