Maui icon indicating copy to clipboard operation
Maui copied to clipboard

TouchBehavior error when attached to a Grid where there are multiple elements overlaying on the same row and some elements are initially not visible

Open JosHuybrighs opened this issue 8 months ago • 3 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Did you read the "Reporting a bug" section on Contributing file?

  • [X] I have read the "Reporting a bug" section on Contributing file: https://github.com/CommunityToolkit/Maui/blob/main/CONTRIBUTING.md#reporting-a-bug

Current Behavior

It seems that attaching a TouchBehavior to a Grid, like in the next example, gives a problem when the visibility of an element that overlays another element on a row is changed from not visible to visible as a result of executing a touch command.

MainPage.xaml:

<CollectionView x:Name="ItemsCollectionView"
                ItemsSource="{Binding Items}"
                SelectionMode="None"
                RemainingItemsThreshold="10">
  <CollectionView.ItemTemplate>
    <DataTemplate x:DataType="vm:ItemViewModel">
      <Grid HeightRequest="130">
        <Grid.Behaviors>
          <tk:TouchBehavior Command="{Binding BindingContext.SelectItemCommand, Source={x:Reference ItemsCollectionView}}"
                            CommandParameter="{Binding .}"
                            DefaultAnimationDuration="250"
                            DefaultAnimationEasing="{x:Static Easing.CubicInOut}"
                            PressedOpacity="0.6"
                            PressedScale="0.8" />
        </Grid.Behaviors>
        <Image Source="{Binding ThumbnailImageSource}"
               Aspect="AspectFill"
               Margin="1"/>
        <Image Source="checked.png"
               IsVisible="{Binding IsSelected}"
               WidthRequest="24"
               VerticalOptions="Start"
               HorizontalOptions="Start"
               Margin="12"/>
      </Grid>
    </DataTemplate>
  </CollectionView.ItemTemplate>
</CollectionView>

MainViewModel.cs:

    public partial class MainViewModel: ObservableObject
    {
        [ObservableProperty]
        ObservableCollection<ItemViewModel> _items = new ObservableCollection<ItemViewModel>();

        [RelayCommand]
        void SelectItem(ItemViewModel itemVM)
        {
            itemVM.IsSelected = !itemVM.IsSelected;
            Debug.WriteLine($"SelectItem - Selected = {itemVM.IsSelected}");
        }

        public MainViewModel()
        {
            _items.Add(new ItemViewModel() { ThumbnailImageSource = "dotnet_bot.png"});
        }
    }

ItemViewModel.cs:

    public partial class ItemViewModel: ObservableObject
    {
        [ObservableProperty]
        bool _isSelected;


        [ObservableProperty]
        ImageSource _thumbnailImageSource;
    }

What happens:

  • The 1st time SelectItemCommand is executed it sets IsSelected on the item to true. As a result of this the IsVisible of the checked.png ImageSource is set to True but it doesn't display.
  • The 2nd time the command executes IsSelected is set to False and IsVisible is set to False.
  • The 3rd time the command executes IsVisible is again set to True and now the icon shows.

Expected Behavior

TouchBehavior should not have impact on possible IsVisible properties of child elements of the element on which it is attached.

In this particular case the solution is to make all overlaying elements visible from the start and dynamically assign the ItemsSource depending on whether IsSelected is set, i.e. using a Converter, like so:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MauiApp1"
             xmlns:tk="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:DataType="vm:MainViewModel"
             x:Class="MauiApp1.MainPage">
  
  <ContentPage.Resources>
    <ResourceDictionary>
      <tk:BoolToObjectConverter x:Key="HideableCheckedIconConverter" TrueObject="checked.png" FalseObject="" />
    </ResourceDictionary>
  </ContentPage.Resources>


  <VerticalStackLayout Padding="30,0"
                       Spacing="25">
    <CollectionView x:Name="ItemsCollectionView"
                    ItemsSource="{Binding Items}"
                    SelectionMode="None"
                    RemainingItemsThreshold="10">
      <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="vm:ItemViewModel">
          <Grid HeightRequest="130">
            <Grid.Behaviors>
              <tk:TouchBehavior Command="{Binding BindingContext.SelectItemCommand, Source={x:Reference ItemsCollectionView}}"
                                CommandParameter="{Binding .}"
                                DefaultAnimationDuration="250"
                                DefaultAnimationEasing="{x:Static Easing.CubicInOut}"
                                PressedOpacity="0.6"
                                PressedScale="0.8" />
            </Grid.Behaviors>
            <Image Source="{Binding ThumbnailImageSource}"
                   Aspect="AspectFill"
                   Margin="1"/>
            <Image Source="{Binding IsSelected, Converter={StaticResource HideableCheckedIconConverter}}"
                   WidthRequest="24"
                   VerticalOptions="Start"
                   HorizontalOptions="Start"
                   Margin="12"/>
          </Grid>
        </DataTemplate>
      </CollectionView.ItemTemplate>
    </CollectionView>
    </VerticalStackLayout>

</ContentPage>

Steps To Reproduce

  1. Open and run solution mauiapp_touchbehavior_issue.zip
  2. Tap on the image.

Link to public reproduction project repository

https://1drv.ms/u/s!AugQvFxkydtIirdJQ7c6wOiMsvSI-w?e=FFiplk

Environment

- .NET MAUI CommunityToolkit: 9.0.0
- OS: Windows 11
- .NET MAUI: 8.0

Anything else?

No response

JosHuybrighs avatar Jun 03 '24 09:06 JosHuybrighs