Xamarin.Forms - ImageButtons in Expander do nothing as they're clicked

31 Views Asked by At

So I have a collectionview and inside of that I have an expander with 3 buttons. The problem is that once I touch one of these 3 buttons they don't do nothing even if they're binded to commands.

Here's how it looks like:

Here's the code:

<CollectionView HorizontalScrollBarVisibility="Never" 
                Margin="0,5,20,15"
                ItemsSource="{Binding Books}"
                VerticalOptions="StartAndExpand"
                ItemsLayout="HorizontalList"
                HeightRequest="210">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout Margin="8,0">
                <xct:Expander>
                    <xct:Expander.Header>
                        <Grid RowDefinitions="*,auto">
                            <PanCake:PancakeView Grid.Row="0" Margin="0,0,20,0">
                                <ffimageloading:CachedImage Source="{Binding Cover}" HeightRequest="200" WidthRequest="145" Aspect="Fill"/>
                            </PanCake:PancakeView>
                            <Label Text="{Binding Title}" FontSize="14" Grid.Row="1" HorizontalOptions="Start" FontFamily="Inter" WidthRequest="145" LineBreakMode="TailTruncation" MaxLines="2" FontAttributes="Bold" TextColor="Black"/>
                        </Grid>
                    </xct:Expander.Header>
                    <xct:Expander.ContentTemplate>
                        <DataTemplate>
                            <StackLayout Orientation="Horizontal" Margin="0,10,0,0">
                                <ImageButton Source="trash_24.png" BackgroundColor="Transparent" HorizontalOptions="Start" Command="{Binding RemoveBookFromCollection}" CommandParameter="{Binding .}" Margin="0,0,0,0">
                                </ImageButton>
                                <ImageButton Source="cross_24.png" BackgroundColor="Transparent" Command="{Binding SetBookAvailability}" CommandParameter="{Binding .}" WidthRequest="24" HeightRequest="24" HorizontalOptions="Start"  Margin="10,0,0,0">
                                </ImageButton>
                                <ImageButton Source="check_24.png" BackgroundColor="Transparent" Command="{Binding SetBookAvailability}" CommandParameter="{Binding .}" HorizontalOptions="Start" Margin="10,0,0,0">
                                </ImageButton>
                            </StackLayout>
                        </DataTemplate>
                    </xct:Expander.ContentTemplate>
                </xct:Expander>                                   
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>
1

There are 1 best solutions below

0
Julian On BEST ANSWER

The DataTemplate has a different BindingContext than the rest of the Page. The DataTemplate inherits its BindingContext from each book instance in the Books collection. You need to use a relative binding in your command binding expression, e.g.:

Command="{Binding RemoveBookFromCollection, Source={RelativeSource AncestorType={x:Type viewModel:YourViewModel}}"

This will become apparent in the IDE, if you provide the x:DataType to the DataTemplate.

You also don't need the ContentTemplate for the body of the Expander, since you're directly providing the content yourself.

Since you didn't show the ViewModel, I will use a generic name, so you'll have to adapt it to your needs to make it work:

<CollectionView
    ItemsSource="{Binding Books}">
    <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="model:Book">
            <xct:Expander>
                <xct:Expander.Header>
                    <Grid RowDefinitions="*,auto">
                        <PanCake:PancakeView Grid.Row="0" Margin="0,0,20,0">
                            <ffimageloading:CachedImage Source="{Binding Cover}" HeightRequest="200" WidthRequest="145" Aspect="Fill"/>
                        </PanCake:PancakeView>
                        <Label Text="{Binding Title}" FontSize="14" Grid.Row="1" HorizontalOptions="Start" FontFamily="Inter" WidthRequest="145" LineBreakMode="TailTruncation" MaxLines="2" FontAttributes="Bold" TextColor="Black"/>
                    </Grid>
                </xct:Expander.Header>
                <StackLayout Orientation="Horizontal" Margin="0,10,0,0">
                    <ImageButton
                        Source="trash_24.png"
                        Command="{Binding RemoveBookFromCollection, Source={RelativeSource AncestorType={x:Type viewModel:YourViewModel}}"
                        CommandParameter="{Binding .}">
                    </ImageButton>

                    <!-- etc ... -->

                </StackLayout>
            </xct:Expander>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

The viewModel:YourViewModel should of course be replaced with your actual namespace and ViewModel. The namespace needs to be included in the XAML header of your page as an XML namespace (xmlns) and ideally also provide the x:DataType to the Page in order to use compiled bindings which also helps the IDE in pointing out binding issues to you and it will produce compiler errors for faulty binding expressions, e.g.:

<ContentPage
    xmlns:viewModel="YourProject.SomeFolderWhereTheViewModelExists"
    x:DataType="viewModel:YourViewModel" />

Using the compiled bindings and the x:DataType attribute is entirely optional, though, but will help with binding expressions. or similar.