34
votes

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

4

4 Answers

61
votes

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
                    });
            }
        }
21
votes

That's because you bind to an item in your EintragList - property (that's why your binding to the text-properties like Beginn and Ende work). And the command-binding tries to reach a command in one single item from your list and not from your viewmodel.

Option 1: You set the command in your item-class and handle the tap there.

Option 2: Tell your binding that the source should be your page (and not the single item):

Command="{Binding BindingContext.EditEintragCommand, Source={x:Reference Name=MyPageName}}"

Just be sure, that the name of your pages root-element is set x:Name="MyPageName"

To know, which item fires the command, you can set the CommandParameter property, which is then also send to the command as an object:

CommandParameter="{Binding .}"

Additionaly: When you are using external templates to show the items in your list, you could try something I described in another answer (same principle).

16
votes

If you want to bind Button click than you can also try to use Clicked event in Button attribute Here is my code and its worked for me

  <ListView x:Name="lst1" RowHeight="80">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Vertical" Padding="8,0,8,0">
                        <Label Text="{Binding Fname}" TextColor="#000" FontSize="14" LineBreakMode="TailTruncation" />
                        <Label Text="{Binding Mobile}" TextColor="#000" LineBreakMode="TailTruncation" />
                        <Button Text="Remove" Clicked="Delete" CommandParameter="{Binding ID}" />
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

and code side you can simply implement delete method with an argument like

   public void Delete(Object Sender, EventArgs args)
    {
        Button button = (Button)Sender;
        string ID = button.CommandParameter.ToString();
        // Do your Stuff.....
    }
0
votes

Here is another thing that can catch you by surprise. The binding to the command will never happen, if you accidentally define your ICommand in the ViewModel as a private property.