XF: ListView ICommand Attached Property

Introduction

In this article we are going to look at how we can attach an ICommand object to a listview and have it execute when the user taps a listview item.

So how are we going to do this? We are going to use an attached property. The attached property is a way to move capability from the code behind to your view model where it is accessible to the business logic.

namespace XamlHelpers {
public sealed class ItemTappedCommandListView
{
    /// Define the attached property with a name and a type for the value.
    /// make sure you add in the property changed event handler so that you
    /// can react to changes to the value of the property
    public static readonly BindableProperty ItemTappedCommandProperty =
        BindableProperty.CreateAttached(
            "ItemTappedCommand",
            typeof(ICommand),
            typeof(ItemTappedCommandListView),
            default(ICommand),
            BindingMode.OneWay,
            null,
            PropertyChanged);

    /// This is the event handler that is invoked when the value of the
    /// attached property is changed. All we do is subscribe to the 
    /// ItemTapped property.
    private static void PropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is ListView listView)
        {
            listView.ItemTapped -= ListViewOnItemTapped;
            listView.ItemTapped += ListViewOnItemTapped;
        }
    }

    /// This is the event handler for when an item is tapped. We make sure
    /// that the sender is a list view, its enabled and that the list isn't in
    /// the middle of refreshing.
    /// If all that is ok, retrieve the ICommand object from the property.
    /// if there, we execute the CanExecute method, and if that is True
    /// we can execute the command.
    private static void ListViewOnItemTapped(object sender, ItemTappedEventArgs e)
    {
        if (sender is ListView list && list.IsEnabled && !list.IsRefreshing)
        {
            list.SelectedItem = null;
            var command = GetItemTappedCommand(list);
            if (command != null && command.CanExecute(e.Item))
            {
                command.Execute(e.Item);
            }
        }
    }

    public static ICommand GetItemTappedCommand(BindableObject bindableObject)
    {
        return (ICommand) bindableObject.GetValue(ItemTappedCommandProperty);
    }

    public static void SetItemTappedCommand(BindableObject bindableObject, object value)
    {
        bindableObject.SetValue(ItemTappedCommandProperty, value);
    }
}
}

Now this is how we use it in our XAML.

<ContentPage
    xmlns:u="clr-namespace:XamlHelpers;">

    <ListView ItemsSource="{Binding MenuItems}"
        u:ItemTappedCommandListView.ItemTappedCommand="{Binding CommandNavigate}">
    </ListView>
</ContentPage>