Xamarin Forms Button Command binding inside a ListView

JanMer picture JanMer · Dec 1, 2016 · Viewed 29.2k times · Source

I have the following problem, in my view I have a Listview. In this listview I would like to have two buttons. One for editing the item, one to delete it.

Here is my listview in XAML

<ListView Grid.Row="1" x:Name="ArbeitsEinträgeList" ItemsSource="{Binding EintragList}" SelectedItem="{Binding SelectedItem}">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <ViewCell.View>
              <Grid>
                <Grid.ColumnDefinitions>
                  <ColumnDefinition/>
                  <ColumnDefinition/>
                  <ColumnDefinition/>
                  <ColumnDefinition Width="Auto"/>
                  <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <Label Text="{Binding Titel}" TextColor="{Binding Fehlerhaft, Converter={StaticResource EintragartConverter}}"></Label>
                <Label Grid.Column="1" Text="{Binding Beginn}" TextColor="{Binding BeginnManuell, Converter={StaticResource EintragartConverter}}"></Label>
                <Label Grid.Column="2" Text="{Binding Ende}" TextColor="{Binding EndeManuell, Converter={StaticResource EintragartConverter}}"></Label>
                <Button Grid.Column="3" Command="{Binding EditEintragCommand}" Text="&#xf040;" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
                <Button Grid.Column="4" Command="{Binding DeleteEintragCommand}" Text="&#xF00D;" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
              </Grid>
            </ViewCell.View>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>

In my ViewModel is everything I need, I have tested the commands with a button not in the listview and it works perfect.

If I hover over the binding, the message "Cannot resolve symbol '...'" appears

Cannot resolve symbol

Answer

DParry picture DParry · Dec 1, 2016

Jan,

Since you've used a list view and your commands are inside the DataTemplate, the binding is attached to the binding context of the each individual model in the ItemSource.

A way around this is do do the following:

<ListView Grid.Row="1" x:Name="ArbeitsEinträgeList" ItemsSource="{Binding EintragList}" SelectedItem="{Binding SelectedItem}">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <ViewCell.View>
              <Grid x:Name="Item">
                <Grid.ColumnDefinitions>
                  <ColumnDefinition/>
                  <ColumnDefinition/>
                  <ColumnDefinition/>
                  <ColumnDefinition Width="Auto"/>
                  <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <Label Text="{Binding Titel}" TextColor="{Binding Fehlerhaft, Converter={StaticResource EintragartConverter}}"></Label>
                <Label Grid.Column="1" Text="{Binding Beginn}" TextColor="{Binding BeginnManuell, Converter={StaticResource EintragartConverter}}"></Label>
                <Label Grid.Column="2" Text="{Binding Ende}" TextColor="{Binding EndeManuell, Converter={StaticResource EintragartConverter}}"></Label>
                <Button Grid.Column="3" BindingContext="{Binding Source={x:Reference ArbeitsEinträgeList}, Path=BindingContext}"   Command="{Binding EditEintragCommand}"   CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}" Text="&#xf040;" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
                <Button Grid.Column="4" BindingContext="{Binding Source={x:Reference ArbeitsEinträgeList}, Path=BindingContext}" Command="{Binding DeleteEintragCommand}"  CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}" Text="&#xF00D;" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
              </Grid>
            </ViewCell.View>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>

So you set the binding source to reference the binding context of the list view (i.e your view model or "ArbeitsEinträgeList". You can also set the command parameter to be the binding context of each individual item. As you can see I have x:Name="Item" on the grid and CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}".

Simply, declaring commands like this allows you do define a generic command in your view model and when the command is executed with the command parameter being the binding context of the individual item.

 public ICommand DeleteEintragCommand
        {
            get
            {
                return new Command((e) =>
                    {
                        var item = (e as MyModelObject);
                        // delete logic on item
                    });
            }
        }