How-to nested two ListView?

1 Answer 1373 Views
ListView
Comercializadora Paxia
Top achievements
Rank 1
Iron
Comercializadora Paxia asked on 09 Feb 2023, 01:29 AM

Hello,

Is it possible to nest two ListView each with a different DataSource?

 

Can you give an example, please?

1 Answer, 1 is accepted

Sort by
0
Maria
Telerik team
answered on 10 Feb 2023, 11:05 AM

Hello,

I have created a sample project with two ListView controls The second is added inside the first ListView ItemTemplate. In the project, there are two different DataSources and two collections. Download the provided example, use it as a base and extend it further per your exact scenario.

Regarding to the question for nesting ListViews - It Is possible to add ListView inside ListView, but it is not recommended and let me explain why: ListView control has an internal scrolling mechanism, and you should avoid nesting scrolling controls. There is a warning in the .NET Maui ScrollView documentation: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/scrollview?view=net-maui-7.0 

ScrollView objects should not be nested. In addition, ScrollView objects should not be nested with other controls that provide scrolling, such as CollectionView, ListView, and WebView. 

The same is valid for Telerik .NET MAUI controls that have internal scrolling, controls like: DataGrid, ListView, DataForm, ItemsControl.

Regards,
Maria
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Comercializadora Paxia
Top achievements
Rank 1
Iron
commented on 17 Feb 2023, 07:20 PM

Thanks for the help.
The problem that I am presenting is when I want to bind commands from the detail or nested list, it does not recognize them.


<telerik:RadListView x:Name="SampleList" ItemsSource="{Binding Coleccion}" SelectionMode="None">
            <telerik:RadListView.ItemTemplate>
                <DataTemplate>
                    <telerik:ListViewTemplateCell>
                        <telerik:ListViewTemplateCell.View>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="auto" />
                                    <RowDefinition Height="auto" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>
                                <Label Grid.Row="0" Text="{Binding NameStore}" />
                                <Label Grid.Row="1" Text="{Binding Description}" />
                                <telerik:RadListView x:Name="DetailSampleList" Grid.Row="2" ItemsSource="{Binding Details}" SelectionMode="None">
                                    <telerik:RadListView.ItemTemplate>
                                        <DataTemplate>
                                            <telerik:ListViewTemplateCell>
                                                <telerik:ListViewTemplateCell.View>
                                                    <Grid>
                                                        <Label Text="{Binding NameMark}" />
                                                    </Grid>
                                                </telerik:ListViewTemplateCell.View>
                                            </telerik:ListViewTemplateCell>
                                        </DataTemplate>
                                    </telerik:RadListView.ItemTemplate>
                                    <telerik:RadListView.Commands>
                                        <telerik:ListViewUserCommand Id="ItemTap" Command="{Binding DetailItemTapCommand}" />
                                    </telerik:RadListView.Commands>
                                </telerik:RadListView>
                            </Grid>
                        </telerik:ListViewTemplateCell.View>
                    </telerik:ListViewTemplateCell>
                </DataTemplate>
            </telerik:RadListView.ItemTemplate>
            <telerik:RadListView.Commands>
                <telerik:ListViewUserCommand Id="ItemTap" Command="{Binding ColeccionItemTapCommand}" />
            </telerik:RadListView.Commands>
        </telerik:RadListView>


This is the ViewModel


public partial class NestedListDemoViewModel : ObservableObject
    {
        public NestedListDemoViewModel()
        {
            ObservableCollection<DetailModel> list = new ObservableCollection<DetailModel>();
            list.Add(new DetailModel { DaysLeft = 10, NameMark = "MARK1", PerfectStore = 0, StatusMark = "PENDING" });
            list.Add(new DetailModel { DaysLeft = 5, NameMark = "MARK2", PerfectStore = 0, StatusMark = "PENDING" });
            list.Add(new DetailModel { DaysLeft = 3, NameMark = "MARK3", PerfectStore = 1, StatusMark = "PENDING" });
            list.Add(new DetailModel { DaysLeft = 2, NameMark = "MARK4", PerfectStore = 1, StatusMark = "PENDING" });
            ObservableCollection<DetailModel> list2 = new ObservableCollection<DetailModel>();
            list2.Add(new DetailModel { DaysLeft = 3, NameMark = "MARK1", PerfectStore = 0, StatusMark = "PENDING" });
            list2.Add(new DetailModel { DaysLeft = 6, NameMark = "MARK2", PerfectStore = 0, StatusMark = "PENDING" });
            list2.Add(new DetailModel { DaysLeft = 9, NameMark = "MARK5", PerfectStore = 0, StatusMark = "PENDING" });
            _Coleccion = new ObservableCollection<SampleModel> { 
                new SampleModel { Description = "Description of XXX", Details = list, HasChilds = true, NameStore = "XXX" }, 
                new SampleModel { Description = "Description of YYY", Details = list2, HasChilds = true, NameStore = "YYY"}
            };
        }

        [ObservableProperty]
        ObservableCollection<SampleModel> _Coleccion;

        [RelayCommand]
        void DetailItemTap(ItemTapCommandContext context)
        {
            var item = context.Item;
        }

        [RelayCommand]
        void ColeccionItemTap(ItemTapCommandContext context)
        {
            var item = context.Item;
        }
    }

 

DetailItemTap is not called on the viewModel, can you help me please.
Greetings!!
Lance | Senior Manager Technical Support
Telerik team
commented on 17 Feb 2023, 07:55 PM

Hi Comercializadora Paxia, this is just one of the problems you're going to run into, which is why Maria warned you against it. You have competing commands, Tap for the top control and a Tap for the nested control.

Let's step back and think about this in terms of layers. If you have Tap gesture commands setup for both ListVews, how would the top ListView know that the user's gesture is for the inner ListView?

Here's a diagram to help explain the topic:

There is a solution to this known as chaining (scroll viewers use chaining for example), but this is not something available for tap gestures.

This is the same conceptual black hole anywhere on any platform, when using nested gesture recognition systems, only one of them is going to get the gesture.

Suggestions

If this is what you want to achieve, I recommend using different control for the inner list. A CollectionView with gestures disabled and only use events, or maybe RadItemsControl and use a Button inside the child's ItemTemplate

For example, you can do this with an EventToCommand behavior, and set the normal content to InputTransparent=True:

<DataTemplate>
    <Grid>
        <!-- This Button is invisible ot the user, it's only here to trigger the clicked event-->
        <Button BackgroundColor="Transparent">
            <Button.Behaviors>
                <behaviors:EventToCommandBehavior EventName="Clicked"
                                                  Command="{Binding SomeCommand}"
                                                  CommandParameter="{Binding}"/>
            </Button.Behaviors>
        </Button>

        <!-- The normal content has InputTransparent=True so the user's click/tap reaches the button -->
        <StackLayout InputTransparent="True">
            <Label Text="Your normal content, use InputTransparent to True to allow the Button click event"
                       InputTransparent="True"></Label>
        </StackLayout>
    </Grid>
</DataTemplate>

Ultimately, what you're trying to do currently is not a supported scenario. Toi achieves it, will take some experimentation with workarounds. If you want an official control with hierarchical this will need to be done with a control that supports it, like a TreeView (this isn't in MAUI yet, but we're working on it)

Neil N
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 07 Aug 2024, 12:20 AM

We're in the same boat, having a model like:


public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string CustomerId { get; set; }
    public List<Order> Orders { get; set; }

    public class Order
    {
        public string OrderId { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal OrderTotal { get; set; }
    }
}

 

I thought I'd try using ListView grouping and the GroupHeaderTapCommand so the data was flattened to:


    public class CustomerOrder : INotifyPropertyChanged
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string CustomerId { get; set; }
        public string OrderId { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal OrderTotal { get; set; }

    }
But now I'm stuck trying to show multiple model properties in the group header template.  Is there really no way to do that? If not, is there now a recommended way of implementing this functionality?

 

Yana
Telerik team
commented on 07 Aug 2024, 07:46 AM

Hi Neil,

In general, the BindingContext of the group header template provides all the information about the items in the corresponding group - you can get the group key, Items collection and level - please check here: ListView: Group Header Template.

Other than that, I'd ask you to give us more details on the exact requirement you have - can you send, for example, an image showing the expected result with presenting the data in a ListView control? In this way I can provide more precise instructions on how it can be achieved. 

In addition, recently we released a new .NET MAUI CollectionView control which provides the functionality of the ListView with some enhancements and improved performance. The CollectionView provides grouping and customizable group headers as well.

I look forward to your reply.

Neil N
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 07 Aug 2024, 11:19 AM | edited

Hi Yana. I've attached a runnable project.  Please locate the "Show Customer Name in header" comment in MainPage.xaml to see what I'm after.  The real solution has to work on iOS and has to handle taps on the Customer section and for each order and support load on demand.  It also has to show eight properties from the customer model.

We had the presentation and LOD parts working with nested listviews but then I found this thread which says, "don't do that".

Yana
Telerik team
commented on 07 Aug 2024, 12:10 PM

Hi Neil,

Thank you for sharing the runnable app, it was of great help.

The GroupHeadeContext (which is the BindingContext of the group header) provides Items property which holds a collection of the items of that group. Since all the items are grouped by CustomerId, that suggests they have the same Customer FirstName and LastName.  So, in order to get them in the GroupHeader template, you can use the following approach:

 

<telerik:RadListView.GroupHeaderTemplate>
    <DataTemplate>
        <StackLayout Orientation="Horizontal">
            <!--Show Customer Name in header-->
            <Label Text="{Binding Items[0].FirstName}" FontAttributes="Bold" Padding="10,0" />
            <Label Text="{Binding Items[0].LastName}" FontAttributes="Bold" Padding="10,0" />
        </StackLayout>
    </DataTemplate>
</telerik:RadListView.GroupHeaderTemplate>

Please find attached the updated app for a reference.

On a side note, I'd recommend you migrate the ListView to the CollectionView - the grouping functionality is the same, some small changes will be needed regarding commands. still, the CollectionView provides more flexibility and improved performance. You can take a look at the following topic on the matter: Migrating the Telerik .NET MAUI ListView to CollectionView.

I remain at your disposal if you have any additional questions on this.

Neil N
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 07 Aug 2024, 01:02 PM

Thank you so much! I'd recommend enhancing your ListView and CollectionView documentation to show off this functionality. It's clear in retrospect that this is possible but sometimes an example makes everything "click".
Yana
Telerik team
commented on 07 Aug 2024, 02:00 PM

I am glad I could help.  Indeed, we'll consider adding this approach as a resource in the ListView/CollectionView documentation.
Neil N
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 07 Aug 2024, 02:07 PM

I did look into implementing the CollectionView control and it looks like we might need to stick with ListView until this is implemented: https://feedback.telerik.com/maui/1658176-collectionview-add-cancellation-support-for-group-expand-collapse

Seeing the group collapse (even briefly) when the header is tapped might confuse users.

Yana
Telerik team
commented on 08 Aug 2024, 06:34 AM

Hi Neil,

Indeed, this is currently not supported in the CollectionView, I've updated the internal item with the additional information you provided.

Tags
ListView
Asked by
Comercializadora Paxia
Top achievements
Rank 1
Iron
Answers by
Maria
Telerik team
Share this question
or