Click here to Skip to main content
15,904,339 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
(NOTE: This works fine on android, however, on iOS the event within the collection view will NOT fire when the respective UI element is clicked)

I have a nested Collection view item within a parent collection view item. These collection views work together to create an accordion UI that takes different "ItemTemplates" in order to display different views on the different sections of the accordion using an intermediate template switcher controller. When clicking the topmost section in the accordion, the UI works fine on android and iOS. However, on iOS specifically, when the child section has been tapped, the UI does not expand the child section. As mentioned earlier, this does not seem to be the case on android.

What I have tried:

I have tried setting the height of the relevant parent elements to a fixed value, and I also used "Auto" to expand the height of each grid row in each of the nested collection views' data templates as seen in the code below, however, I cannot figure out why this is only an issue on iOS and NOT also on android. Below is the relevant code that I used to build this accordion UI out:

The relevant main page xaml code:
XML
<ContentPage ....
             x:Name="Form"
             x:DataType="datacollection:MainViewModel"
             ....
            >

<ContentPage.Content>
<Grid RowDefinitions="10000" BackgroundColor="BlanchedAlmond">
<VerticalStackLayout Grid.Row="0" Grid.Column="0" BackgroundColor="Aquamarine">
    ....
        <StackLayout HeightRequest="10000">
            <CollectionView ItemsSource="{Binding DataSections}" HeightRequest="10000">
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="datacollection:DataSection">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="40"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <HorizontalStackLayout Grid.Row="0" Grid.Column="0">
                                <HorizontalStackLayout.GestureRecognizers>
									<!--This event is working fine in the view model-->
                                    <TapGestureRecognizer Command="{Binding BindingContext.SectionTapped, Source={x:Reference Form} }" CommandParameter="{Binding .}" />
                                </HorizontalStackLayout.GestureRecognizers>
                                <Label Text="{Binding Title}" Style="{StaticResource label}" MinimumHeightRequest="40" VerticalTextAlignment="Center" TextColor="{StaticResource normalText}" FontAttributes="Bold" />
                                <Image  Source="{Binding Expanded, Converter={StaticResource expandedImageConverter}}" HorizontalOptions="End" HeightRequest="20" WidthRequest="20" Aspect="AspectFit" />
                            </HorizontalStackLayout>
                            <BoxView Grid.Row="1" Grid.Column="0" Color="#b9b9b9"/>
                            <CollectionView 
                            x:Name="sectionList"
                            Grid.Row="2" 
                            Grid.Column="0" 
                            IsVisible="{Binding Expanded}" 
                            ItemsSource="{Binding SectionItems}" 
                            EmptyView="No items to display" BackgroundColor="White"
                            ItemTemplate="{StaticResource TemplateSelector}"
                        />
						<!--
						However, the event within the selected ItemTemplate from the summary selector 
						component does not fire off event though the binding is set to the same reference 
						as the parent. It just uses a different method that does not get called on iOS for some
						reason.
						-->
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </StackLayout>
        ....
    </VerticalStackLayout>

    ....
</VerticalStackLayout>
</ContentPage.Content>
</ContentPage>


The C# methods used to expand the parent and child CollectionViews to show their content in the main view model:
C#
//Parent section event and method
public ICommand SectionTapped => new Command<DataSection>(OnSectionTapped);

private void OnSectionTapped(DataSection dataSection)
{
    dataSection.Expanded = !dataSection.Expanded;

}

//Child section event and method. Notice how I am trying to catch an error here.

public ICommand ChildSectionTapped => new AsyncCommand<ChildSectionItem>(OnChildSectionTapped);

	private async Task OnChildSectionTapped(ChildSectionItemItem childSectionItem)
{
    try
    {
        if (childSectionItem.Children.Any())
        {
            childSectionItem.Expanded = !childSectionItem.Expanded;
            ....
        }

        await Task.CompletedTask;
    }
    catch (Exception ex) {
        var exc = ex;
    }
}


The relevant template switcher xaml code:
XML
<sessions:TemplateSelector 
	x:Name="TemplateSelector" 
	x:Key="TemplateSelector"
	Template1="{StaticResource Template1}"
	Template2="{StaticResource Template2}"
	Template3="{StaticResource Template3}"
	Template4="{StaticResource Template4}"
	Template5="{StaticResource Template5}"
/>


The relevant template switcher c# code:
C#
public class TemplateSelector : DataTemplateSelector
    {
        public DataTemplate Template1 { get; set; }
        public DataTemplate Template2 { get; set; }
        public DataTemplate Teplate3 { get; set; }
        public DataTemplate Template4 { get; set; }
        public DataTemplate Template5 { get; set; }

        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            if (item.GetType() == typeof(Template1))
            {
                return Template1;
            }

            if (item.GetType() == typeof(Template2))
            {
                return Template2;
            }

            if (item.GetType() == typeof(Template3))
            {
                return Template3;
            }

            if (item.GetType() == typeof(Template4))
            {
                return Template4;
            }

            if (item.GetType() == typeof(Template5))
            {
                return Template5;
            }

            return null;
        }
    }


And last but not least, here is the code for the actual child section template itself which is stored on the "ContentPage.Resources" section of the page.
XML
<DataTemplate x:Key="Template1" x:DataType="datacollection:ChildSectionItem">
    <StackLayout>
        <StackLayout.GestureRecognizers>
            <TapGestureRecognizer Command="{Binding BindingContext.ChildSectionTapped, Source={x:Reference Form}}" CommandParameter="{Binding .}" />
        </StackLayout.GestureRecognizers>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" BackgroundColor="Aqua" RowDefinitions="*" ColumnDefinitions="*">
                <Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*">
                    <HorizontalStackLayout Grid.Row="0" Grid.Column="0" Padding="0, 15, 0, 15">
                        <Label Text="{Binding Title}" Style="{StaticResource boldGridInfo}" Margin="10, 0, 0, 0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" VerticalTextAlignment="Start" TextColor="{StaticResource normalText}"/>
                        <Label Text="{Binding Children.Count, Style="{StaticResource gridInfo}" HorizontalOptions="EndAndExpand"/>
                        <Label Text="{Binding Expanded}"/>
                    </HorizontalStackLayout>
                    <BoxView Grid.Row="2" Grid.Column="0"  HeightRequest="1" Color="#b9b9b9" />
                </Grid>
            </Grid>
            <Grid Grid.Row="1" Grid.Column="0" Padding="5" Margin="0,0,0,0" >
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <CollectionView IsVisible="{Binding Expanded}" ItemsSource="{Binding Children}" Grid.Row="0" Grid.Column="0" BackgroundColor="Bisque">
                    <CollectionView.ItemTemplate>
						.....
					</CollectionView.ItemTemplate>
                </CollectionView>
            </Grid>
        </Grid>
    </StackLayout>
</DataTemplate>


I have no idea why this is not working and not sure if this should be another issue that needs to be reported or if it's something stupid on my part, Though I assume the latter. Anything to help would be appreciated. Thanks.
Posted
Comments
Baraiboapex 13-May-24 15:13pm    
I do apologize for the long question, I just want to display as much information as possible to see if there is anything that I might have missed. Do let me know if any questions come up. Thanks again!
Baraiboapex 13-May-24 15:57pm    
I should also clarify that I also changed the child template to something less complex and it didn't work:
<DataTemplate x:Key="TargetGroupSummaryTemplate" x:DataType="datacollection:ChildSectionItem">
    <VerticalStackLayout HeightRequest="50" BackgroundColor="Bisque">
        <VerticalStackLayout BindingContext="" BackgroundColor="Aqua">
            <VerticalStackLayout.GestureRecognizers>
                <TapGestureRecognizer Command="{Binding BindingContext.ChildSectionTapped, Source={x:Reference Form}}" CommandParameter="{Binding .}"/>
            </VerticalStackLayout.GestureRecognizers>
            <Label Text="U R AN IDIOT HA HAHAHAHAHA" TextColor="Black"/>
        </VerticalStackLayout>
    </VerticalStackLayout>
</DataTemplate>
Baraiboapex 13-May-24 16:28pm    
Lastly, I just tried the following: {Binding
Source={RelativeSource AncestorType={x:Type datacollection:PageViewModel}},
Path=ChildSectionTapped}"
CommandParameter="{Binding Source={RelativeSource Self}}
for the command and command parameter, still no luck

1 solution

So I solved this. Apparently in the latest version of maui, the collection views are NOT a good idea based on my long time of fiddling around with this and research. What you need to do instead is use a bindable layout with something like a stack layout or vertical stack layout (use the latter because it is more performant) and then you will get consistent reliable results. Honestly though, this is quite irksome since the collection views have given me consistent reliable results up to this point.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900