1
<CollectionView.ItemTemplate>
                <DataTemplate x:DataType="data:PhotoItemViewModel">
                    <Border StrokeThickness="1"
                            Padding="0">
                        <VerticalStackLayout>
                            <Grid>
                                <Image
                                    Source="{Binding ThumbnailImageSource}"
                                    Aspect="AspectFill"
                                    HeightRequest="120"
                                    WidthRequest="120">
                                    <Image.Behaviors>
                                        <toolkit:TouchBehavior
                                            
                                            LongPressCommand="{Binding x:DataType=ContentPage, Source={x:Reference Page}, Path=BindingContext.LongPressCommand}"
                                            LongPressCommandParameter="{Binding .}"/>
                                    </Image.Behaviors>
                                </Image>
                                
                                <CheckBox
                                    IsChecked="{Binding IsSelected}"
                                    IsVisible="{Binding x:DataType=ContentPage,Source={x:Reference Page}, Path=BindingContext.IsSelectionMode}"
                                    VerticalOptions="Start"
                                    HorizontalOptions="End"
                                    Margin="5"
                                    BackgroundColor="White"
                                    Opacity="0.8"/>
                            </Grid>
                        </VerticalStackLayout>
                    </Border>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

Here I'm using a collection view to display a list of images, with the support of long press gesture on each image, implemented using CommunityToolkit.Maui's TouchBehavior. And my view model's LongPressCommand command is initialized with this method:

  private void OnPhotoLongPressed(PhotoItemViewModel photo)
    {
        IsSelectionMode = true;
        // photo.IsSelected = true;
    }

Now the issue is the photo passed from the command is always null.

1
  • Whilst this isn't directly what you asked for, if you consider deriving from Image, say, MyImage and add the TouchBehavior to your subclass then your component will have access to everything including the BindingContext. Commented Jul 10 at 9:08

3 Answers 3

1

Turns out there're just couple of things to add in order to have my original code to work:

  1. Add BindingContext assignment to the behavior;

  2. Set x:DataType to the BindingContext;

  3. Use x:Reference to refer to the parent Image control and set its BindingContext to the behavior.

Hope this could be added to the documentation as this is quite a common scenario.

Sign up to request clarification or add additional context in comments.

Comments

0

".NET MAUI does not set the BindingContext of a behavior"

Name the Grid:

<Grid x:Name="grid"

Add a BindingContext reference in LongPressCommandParameter:

LongPressCommandParameter="{Binding Source={x:Reference grid}, Path=BindingContext, x:DataType=Grid}"

The same as above in codebehind:

First, add Loadedand Unloaded in xaml:

<Grid x:Name="grid" Loaded="AddBehavior" Unloaded="ClearBehaviors">

Codebehind (.xaml.cs) (with your viewmodel named ViewModel and LongPressCommand named LongPressCommand):

AddBehavior:

if (sender is Grid grid)
{
    var behavior = new TouchBehavior();
    behavior.SetBinding(TouchBehavior.LongPressCommandProperty, static (Page p) => (p.BindingContext as ViewModel).LongPressCommand, source: page);
    behavior.SetBinding(TouchBehavior.LongPressCommandParameterProperty, static (Grid g) => g.BindingContext, source: grid);

    grid.Behaviors.Add(behavior);
}

ClearBehaviors:

if (sender is Grid grid)
{
    foreach (var behavior in grid.Behaviors)
    {
        behavior.RemoveBinding(TouchBehavior.LongPressCommandParameterProperty);
        behavior.RemoveBinding(TouchBehavior.LongPressCommandProperty);
    }
    grid.Behaviors.Clear();
}

This avoids the XamlC warning XC0045: Binding: Property "LongPressCommand" not found on "System.Object".

6 Comments

Care to explain why my code didn't work?
I read the official document before posting here. Unfortunately it doesn't provide examples with command parameters.
I could be mistaken but the reason it didn't work is because your Image object is bound to ThumbnailImageSource not PhotoItemViewModel. Not sure if MAUI has the concept of ancestors but you could have also used that when binding to go up one level so that "Binding ." was binding to PhotoItemViewModel instead of ThumbnailImageSource, which could not be converted to PhotoItemViewModel. If you change your previous code to have the method accept type ThumbnailImageSource you might get a value. Hope that clears it up for you
ThumbnailImageSource is the name of a property of PhotoItemViewModel. Technically speaking, using Binding . is supposed to pass the entire bound object, which is the view model, to the backend command.
The grid is inside the ItemTemplate, meaning there'll be multiple grids, so I assume I can't name it and reference it as if there were only 1 grid on the page.
0

Refactoring Image into MyImage would have reduced the binding complexity of this problem.

// MyImage.cs
public partial class MyImage : Image
{
    [BindableProperty] public partial ICommand? LongPressedCommand { get; set; }
    [BindableProperty] public partial object? LongPressedCommandParameter { get; set; }
    public MyImage()
    {
        var behavior = new TouchBehavior();
        behavior.SetBinding(
            TouchBehavior.LongPressCommandProperty, static (MyImage i) => i.LongPressedCommand,
            BindingMode.OneWay,
            source: this);
        behavior.SetBinding(
            TouchBehavior.LongPressCommandParameterProperty, static (MyImage i) => i.LongPressedCommandParameter,
            BindingMode.OneWay,
            source: this);
        this.Behaviors.Add(behavior);
    }
}
<ContentPage
    x:Class="StackOverflow.Maui.App.SO79696605.MainPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:so79696605="clr-namespace:StackOverflow.Maui.App.SO79696605"
    x:DataType="so79696605:MainPage">
    <CollectionView ItemsSource="{Binding Photos}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="so79696605:PhotoItemViewModel">
                <Border Padding="0" StrokeThickness="1">
                    <VerticalStackLayout>
                        <Grid>
                            <so79696605:MyImage
                                Aspect="AspectFill"
                                HeightRequest="120"
                                LongPressedCommand="{Binding ImageLongPressedCommand, Source={RelativeSource AncestorType={x:Type so79696605:MainPage}}, x:DataType='so79696605:MainPage'}"
                                LongPressedCommandParameter="{Binding .}"
                                Source="{Binding ThumbnailImageSource}"
                                WidthRequest="120" />

                            <CheckBox
                                Margin="5"
                                BackgroundColor="White"
                                HorizontalOptions="End"
                                IsChecked="{Binding IsSelected, Mode=TwoWay}"
                                Opacity="0.8"
                                VerticalOptions="Start" />
                        </Grid>
                    </VerticalStackLayout>
                </Border>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.