Xamarin Forms ListView ItemTapped/ItemSelected Command Binding on XAML

40,180

Solution 1

I am not sure why you need to give Item Selected or Item Tapped event in your page when you can directly get the selected / tapped object directly in your ViewModel:

I think you've bind the listview with below types of code

<ListView ItemsSource="{Binding PermitDetails}" 
SelectedItem="{Binding objItemSelected, Mode=TwoWay}" x:Name="lst" 
RowHeight="35" HorizontalOptions="FillAndExpand" 
VerticalOptions="Fill">

And in the View Model which you've bind with the page, you've to define the property objItemSelected as mentioned in below code

private Permit _ItemSelected;
public Permit objItemSelected {
    get {
        return _ItemSelected;
    }
    set {
        if (_ItemSelected != value) {
            _ItemSelected = value;
            OnPropertyChanged ("ItemSelected");
        }
    }
}

And if you want to perform any additional functionality like navigating to detail page, you can do it from the set property after OnPropertyChanged statement is executed.

Hope this helps!

Solution 2

This is an old question, and maybe this is a fairly recent development, but you can use the Behaviors on any control to convert an event into an ICommand.

An example...

<ListView ItemsSource="{Binding Tags}"
            SelectedItem="{Binding SelectedTag}">
    <ListView.Behaviors>
        <behaviors:EventHandlerBehavior EventName="ItemSelected">
            <behaviors:InvokeCommandAction Command="{Binding SelectedTagChanged}" />
        </behaviors:EventHandlerBehavior>
    </ListView.Behaviors>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ContentView Padding="8">
                    <Label Text="{Binding DisplayValue}" />
                </ContentView>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

In this example, the ItemSelected event will map to the SelectedTagChanged command in your view model which looks like this...

public Command SelectedTagChanged
{
    get
    {
        return new Command(row =>
        {
            // do something
        });
    }
}

Solution 3

My scenario is a keypad and images are the buttons and when one is clicked then the relevant character is showed in a label.

So..

Lets say you have the follow control(key 1):

<Image  x:Name="imgKey1"
        Source="key1.png"
        Aspect="AspectFit" />

And you want when the image is tapped to trigger a command from you "viewModel" object. My "viewModel" has the follow property:

public ICommand AddCharCommand { protected set; get; }

where in my class(view model) constructor i have:

  this.AddCharCommand = new Command<string>((key) =>
            {
                // Add the key to the input string.
                this.InputString += key;
            });

"InputString" is a string property...

So for binding the view and the mode,l i am doing the follow:

  imgKey1.GestureRecognizers.Add(new TapGestureRecognizer
        {
            Command = viewModel.AddCharCommand,
            CommandParameter = "1",
        });

I hope that i help you, if somebody need something and i can help; i am here...and there. JJ

IN XAML 17-11-14

      <Image  Source="n1normal.png"
              Aspect="AspectFit" >
        <Image.GestureRecognizers>
          <TapGestureRecognizer
            Command="{Binding AddCharCommand}"
            CommandParameter ="1"/>
        </Image.GestureRecognizers>
      </Image>

//-OR-

        <Image Source="magnifyglass.png"
               Aspect="AspectFit"
               HorizontalOptions="End">
          <Image.GestureRecognizers>
            <TapGestureRecognizer Tapped="Search"/>
          </Image.GestureRecognizers>  
        </Image>

//And for the Search create in your ViewModel

 private void Search(object sender, EventArgs e)
 {
      //Your code here
 }

Solution 4

I used to take the approach of binding selected item into the view model, but that tended to raise trouble filtering out programmatic changes versus user action. My personal favorite is an attached property.

public static readonly BindableProperty ListItemTappedCommandProperty = BindableProperty.CreateAttached<AttachedProperties, ICommand>(
    staticgetter: o => (ICommand) o.GetValue(ListItemTappedCommandProperty), 
    defaultValue: default(ICommand),
    propertyChanged: (o, old, @new) =>
    {
        var lv = o as ListView;
        if (lv == null) return;

        lv.ItemTapped -= ListView_ItemTapped;
        lv.ItemTapped += ListView_ItemTapped;
    });

private static void ListView_ItemTapped(object sender, object item)
{
    var lv = sender as ListView;

    var command = (ICommand) lv?.GetValue(ListItemTappedCommandProperty);
    if (command == null) return;

    if (command.CanExecute(item))
        command.Execute(item);
}

...and then set on a ListView with:

controls:AttachedProperties.ListItemTappedCommand="{Binding ItemSelectedCommand}"

It's possible that this could even be extended to take the event name and apply more generally, but that is an exercise for another time.

Share:
40,180
MarcioGomes
Author by

MarcioGomes

Updated on February 11, 2022

Comments

  • MarcioGomes
    MarcioGomes over 2 years

    How can I bind a ICommand object from my ViewModel (currently in BindingContext) to the ItemTapped or ItemSelected from a ListView in XAML?

    This is a simple task when using a Button, I just set Command="MyViewModelCommand" and everything works.