Group by show only first child open

1 Answer 127 Views
ListView
Daniel
Top achievements
Rank 1
Silver
Bronze
Daniel asked on 27 Apr 2022, 11:49 AM

Hi,

This list view is using group by.

I want the first item to be open all other items of grouping will be closed  it possible?

       <telerikDataControls:RadListView ItemsSource="{Binding RulesSource, Mode=TwoWay}" x:Name="rulesListView" 
                
                >
                <telerikDataControls:RadListView.SelectedItemStyle>
                    <telerikListView:ListViewItemStyle BackgroundColor="#83A9E2"
                                    TextCellTextColor="#AAC7F6"
                                    BorderColor="#0A3A82"
                                    BorderWidth="2"
                                    BorderLocation="Bottom"/>
                </telerikDataControls:RadListView.SelectedItemStyle>
                <telerikDataControls:RadListView.PressedItemStyle>
                    <telerikListView:ListViewItemStyle BackgroundColor="#C1C1C1"
                                    TextCellTextColor="#AAC7F6"
                                    BorderColor="#0B3D89"
                                    BorderWidth="2"
                                    BorderLocation="Bottom"/>
                </telerikDataControls:RadListView.PressedItemStyle>
                <telerikDataControls:RadListView.ReorderItemStyle>
                    <telerikListView:ListViewItemStyle BackgroundColor="#0B3D89"
                                    TextCellTextColor="#AAC7F6"
                                    BorderColor="Black"
                                    BorderWidth="2"
                                    BorderLocation="All" />
                </telerikDataControls:RadListView.ReorderItemStyle>
                <telerikDataControls:RadListView.GroupDescriptors>
                    <telerikListView:PropertyGroupDescriptor PropertyName="Portal" />
                </telerikDataControls:RadListView.GroupDescriptors>
                <telerikDataControls:RadListView.ItemTemplate>
                    <DataTemplate>
                        <telerikListView:ListViewTemplateCell>
                            <telerikListView:ListViewTemplateCell.View>
                                <telerik:RadBorder  BorderColor="{DynamicResource PrimaryColor}" BorderThickness="1"   VerticalOptions="Center" CornerRadius="5" Margin="5" >
                                    <Grid HeightRequest="200" RowSpacing="10" RowDefinitions="auto, auto, auto, auto, auto" ColumnSpacing="10" ColumnDefinitions="auto, auto, auto, auto" HorizontalOptions="Center" VerticalOptions="Center">
                                        <Label Grid.Row="0" Grid.Column="0" Text="Capacity (Mega):" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="0" Grid.Column="1" Text="{Binding Capacity}" TextColor="Black" VerticalOptions="Center" />
                                        <Label Grid.Row="0" Grid.Column="2" Text="Capacity in used (Mega):" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="0" Grid.Column="3" Text="{Binding CapacityUsed}" TextColor="Black" VerticalOptions="Center" />

                                        <Label Grid.Row="1" Grid.Column="0" Text="Scan capacity (Mega/Mounth):" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="1" Grid.Column="1" Text="{Binding ScanCapacity}" TextColor="Black" VerticalOptions="Center" />
                                        <Label Grid.Row="1" Grid.Column="2" Text="Scan capacity in used: (Mega/Mounth)" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="1" Grid.Column="3" Text="{Binding ScanCapacityUsed}" TextColor="Black" VerticalOptions="Center" />

                                        <Label Grid.Row="2" Grid.Column="0" Text="File type black list:" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="2" Grid.Column="1" Text="{Binding FileTypeBlackList}" TextColor="Black" VerticalOptions="Center" />
                                        <Label Grid.Row="2" Grid.Column="2" Text="File type black list:" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="2" Grid.Column="3" Text="{Binding FileTypeWhiteList}" TextColor="Black" VerticalOptions="Center" />

                                        <Label Grid.Row="3" Grid.Column="0" Text="Max single file size: (Mega)" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="3" Grid.Column="1" Text="{Binding MaxSingleFileSize}" TextColor="Black" VerticalOptions="Center" />
                                        <Label Grid.Row="3" Grid.Column="2" Text="Max files in job: (Mega)" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="3" Grid.Column="3" Text="{Binding MaxFilesInJob}" TextColor="Black" VerticalOptions="Center" />
                                       
                                        <Label Grid.Row="4" Grid.Column="0" Text="Max total files size in job: (Mega)" TextColor="Black" VerticalOptions="Center" FontSize="16" FontAttributes="Bold" Margin="5"/>
                                        <Label Grid.Row="4" Grid.Column="1" Text="{Binding MaxSingleFileSize}" TextColor="Black" VerticalOptions="Center" />


                                    </Grid>
                                </telerik:RadBorder>
                            </telerikListView:ListViewTemplateCell.View>
                        </telerikListView:ListViewTemplateCell>
                    </DataTemplate>
                </telerikDataControls:RadListView.ItemTemplate>
                <telerikDataControls:RadListView.LayoutDefinition>
                    <telerikListView:ListViewLinearLayout ItemLength="200" />
                </telerikDataControls:RadListView.LayoutDefinition>
            </telerikDataControls:RadListView>

1 Answer, 1 is accepted

Sort by
0
Lance | Manager Technical Support
Telerik team
answered on 27 Apr 2022, 12:25 PM

Hello Daniel,

Please visit the following documentation on expanding and collapsing groups .NET MAUI ListView Documentation | Expand and Collapse Groups.

As a tip, some sections of the documentation can be expanded. If you expand those sections, you will find subtopics on the thing you're looking for

Alternatively, use the search bar at the top of the documentation. In this case, it would have been the first result:

 

Regards,
Lance | Manager Technical Support
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/.

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 27 Apr 2022, 12:46 PM | edited

Hi,

The code there is not in MVVM manner.

How is can be done in MVVM manner ?

var dataView = rulesListView.GetDataView();
		var rootGroups = dataView.GetGroups();
		dataView.ExpandGroup(rootGroups.First());

Lance | Manager Technical Support
Telerik team
commented on 27 Apr 2022, 01:00 PM

There is such thing as a BindableProperty for a method in .NET. To your question on how to use methods and events in MVVP, I cannot answer that for you, implementing MVVM is up to the developer.

I would suggest learning about Behaviors, which you can use for things like events and methods. See the Microsoft Documentation Behaviors - .NET MAUI | Microsoft Docs. Please carefully follow the tutorial "Creating a MAUI Behavior" where you'll learn how to subscribe to an event in an MVVM friendly manner. Once you are done with that tutorial, you'll understand how you can use UI code that is not tightly coupled to the view.

Alternatively, you can create an Interface that exposes a couple methods. Then implement the interface in the code behind and you can call that  interface method from the view model.

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 27 Apr 2022, 02:21 PM

Thanks,

I used second approach,  Get null refrence , why ?


  public interface  IRules  
    {
        void SetFirstGroupColapaseOpenOnly();
    }

public partial class RulesView : ContentView, IRules
{
	public RulesView()
	{
         InitializeComponent();
        this.BindingContext = new RulesViewModel(this);
    }

    public void SetFirstGroupColapaseOpenOnly()
    {
        var dataView = rulesListView.GetDataView();
        var rootGroups = dataView.GetGroups();//Get null reference
        dataView.ExpandGroup(rootGroups.First());
    }
}

public class RulesViewModel : BaseViewModel
	{

		
		public RulesViewModel(IRules rules)
		{
			RulesSource = new ObservableCollection<Rule>();
			GetRules();
			rules.SetFirstGroupColapaseOpenOnly();
		}

Lance | Manager Technical Support
Telerik team
commented on 27 Apr 2022, 03:29 PM

I wouldn't be able to say why without having a runnable project to debug, but it looks like you are calling rules.SetFirstGroupColapaseOpenOnly far too early... the page has not had a chance to render yet... let alone create groups.

Remember, nothing is real until it has been created. The view model's constructor is executed before the page has even loaded, the RadListView isn't rendered yet, and most certainly hasn't been able to load up items and create groups. The page constructor is not a good place to do any of this, its only good for instantiating things that will be needed later.

Timing - Solution

When it comes to things that need the UI to be ready, wait until at least OnAppeared has been executed.. even then, you sometimes have to wait about 200-500 milliseconds to give the UI to generate extra things (i.e. generate groups after ItemsSource is bound).

So, how would you handle this? Again, this is custom architecture guidance that I cannot provide an answer for. If it were me, I'd look at expanding the functionality of your interface so that it can let the view model know when the page is done being loaded. for example an event that can let all view model subscribers know the page is ready.

Suggestion

However, I do not want to give you this kind of advanced architecture setup because I am unable to continue supporting it. So, let me propose a simpler option... use the RadListView's Loaded event.

private void RulesListView_Loaded(object sender, EventArgs e)
{
    if(sender is RadListView listView)
    {
        Task.Delay(500);

        var dataView = listView?.GetDataView();

        // ALWAYS check for null (use null accessors for concise appearance)
        var rootGroups = dataView?.GetGroups();
        var firstGroup = rootGroups?.First();

        if (firstGroup != null)
            dataView.ExpandGroup(firstGroup);
    }
}

This will not only let you know when the page is ready, but also when the RadListView is almost ready

MVVM Consideration

As far as MVVM goes, there are many different implementations for an EventToCommandBehavior. For an easy one, use the MAUI Toolkit's EventToCommandBehavior on the RadListView's Loaded event (if you want more control over what parameter is passed, you can just copy my EventToCommandBehavior class).

Now that you have access to the Loaded event, you can use the sender (or command parameter) to have a reference to the RadListView. then give it a small pause to generate the groups and you're done:

Here's what it would look like as a command delegate:

Final Fallback Option

You can also just pass up the OnAppearing method to the viewmodel:

Page

View model

Note: most MVVM toolkits have some form of this "OnAppearing" implementation in the BaseViewModel class anyways. Try seeing what yours has to offer before adding an OnAppearing method to your view model base

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 28 Apr 2022, 06:05 AM

I used view not page.

1. Using the RadListView's Loaded event  I failed  on this row:var firstGroup = rootGroups?.First();

2.Using behaviors:Is not complied:


   xmlns:behaviors="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
<telerikDataControls:RadListView.Behaviors>
                    <behaviors:EventToCommandBehavior
                EventName="Loaded"
                Command="{Binding LvLoadedCommand}" />
                </telerikDataControls:RadListView.Behaviors>

Lance | Manager Technical Support
Telerik team
commented on 28 Apr 2022, 12:17 PM

You must give the UI time to load the items and create the groups before you can collapse/expand any. This is the bottom line. If you are having trouble with custom implementation, go back to the beginning and follow the path of execution and ensure that all the groups are ready before getting the DataView.

Add more time to your delay, or make sure you are awaiting the Task.Delay properly (use breakpoints to confirm the logic is delaying for the duration you have set). 

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 28 Apr 2022, 12:23 PM | edited

#2  why xmlns:behaviors="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" is not complied in view ?
Lance | Manager Technical Support
Telerik team
commented on 28 Apr 2022, 12:26 PM

I have no idea, that's not a Telerik control. Did you forget to add their NuGet packages? Please follow the MAUI Toolkit instructions.
Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 04 May 2022, 06:33 AM

I added this package and got this error:

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 11 May 2022, 07:07 AM

Can you help in this issue?
Didi
Telerik team
commented on 11 May 2022, 07:23 AM

The issue is not related to the Telerik UI for .NET MAUI controls. For general questions related to .NET MAUI you can use for example the GitHub Maui issues or Microsoft Q&A.
Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 15 May 2022, 03:11 PM | edited

I fix this issue by:


  public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            // Initialise the toolkit
            builder.UseMauiApp<App>().UseMauiCommunityToolkit();

But the command not fire I  init it in Cto'r as follow:


	public RulesViewModel()
		{
			RulesSource = new ObservableCollection<Rule>();
			InitBusyIndicator();
            InitCommands();
            GetRules();
			
		}


private void InitCommands()
		{
			RulesLoadedCommand = new Command<RadListView>(RulesLoaded);


		}

        private void RulesLoaded(RadListView listView)
        {
			Task.Delay(500);
			var dataView = listView?.GetDataView();
			var rootGroups = dataView?.GetGroups();
			var firstGroup = rootGroups?.First();

			if (firstGroup != null)
				dataView.ExpandGroup(firstGroup);
		}
        #endr
I think I need to pass in CommandParameter the RadListView itself, how is done?
Lance | Manager Technical Support
Telerik team
commented on 16 May 2022, 12:21 PM

Hi Daniel, that decision is up to you. If you want to pass a reference to a UI element to your view model and break your MVVM purity, you can do that (but you've been very adamant about sticking to pure MVVM). Otherwise, you can design an interface to communicate with the view.

I am unable to write a new interface-based MVVM architecture for you, but you can look at one of our demos that do this. Here are the interfaces the CRM demo uses (search the rest of the code for the interface to see how it is used).

Ultimately, the architecture of your app is up to you, this isn't something we can provide guidance for. I do have two suggestions for external help... 1) If you would like to talk to other developers about MVVM, you can post on StackOverflow. 2) Alternatively, if you would like a professional engineer to consult with, you can contact the Outsourcing Services team here.

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 17 May 2022, 08:36 AM | edited

1. I used the interface approach but  all items are expanded not one

  public interface IRules
    {
        void SetFirstGroupColapaseOnlyOpen();
        event RulesPageReadyEvent RulesPageReady;
    }

    public delegate void RulesPageReadyEvent(object sender, EventArgs args);

3.View code behind- see in bold why I get null there?


public partial class RulesView : ContentView, IRules
{
	public RulesView()
	{
         InitializeComponent();

        this.BindingContext = new RulesViewModel(this);
    }

    public event RulesPageReadyEvent RulesPageReady;

    public void SetFirstGroupColapaseOnlyOpen()
    {
        if (rulesListView != null)
        {
            Task.Delay(500);

            var dataView = rulesListView?.GetDataView();

            // ALWAYS check for null (use null accessors for concise appearance)
            var rootGroups = dataView?.GetGroups();
            var firstGroup = rootGroups?.FirstOrDefault();

            if (firstGroup != null)
                dataView.ExpandGroup(firstGroup);
        }
    }

    private void OnRulesListViewLoaded(object sender, EventArgs e)
    {
        if (sender is RadListView listView)
        {
            RulesPageReady.Invoke(this, EventArgs.Empty);
        }
    }
}

3.View model:


public RulesViewModel(IRules rules) { RulesSource = new ObservableCollection<Rule>(); InitBusyIndicator(); InitCommands(); rules.RulesPageReady += Rules_RulesPageReady; } private async void Rules_RulesPageReady(object sender, EventArgs args) {

await GetRules();

(sender as RulesView).SetFirstGroupColapaseOnlyOpen(); //(sender as RulesView)..RulesPageReady -= Rules_RulesPageReady; }


Lance | Manager Technical Support
Telerik team
commented on 17 May 2022, 07:17 PM

All items are expanded by default. Please visit the docuimentation .NET MAUI ListView Documentation | Expand and Collapse Groups | Telerik UI for .NET MAUI

If you only want one item expanded, you can either iterate over all the groups and collapse all the ones you dont want expanded. Or even easier, just call CollapseAll.. wait a few milliseconds, then expand the first one.

Daniel
Top achievements
Rank 1
Silver
Bronze
commented on 18 May 2022, 03:24 AM

The fixed is:

	private async void Rules_RulesPageReady(object sender, EventArgs args)
		{
			var rulesView = sender as RulesView;

			if (rulesView != null)
			{
				_rules.RulesPageReady -= Rules_RulesPageReady;
                await GetRules();
                rulesView.SetFirstGroupColapaseOnlyOpen();
			}
		     	
           
         }




 public void SetFirstGroupColapaseOnlyOpen()
    {
        if (rulesListView != null)
        {
           
             var dataView = rulesListView?.GetDataView();
            dataView.CollapseAll();

            Task.Delay(500);

            var rootGroups = dataView?.GetGroups();
            var firstGroup = rootGroups?.FirstOrDefault();

            if (firstGroup != null)
                dataView.ExpandGroup(firstGroup);
        }
    }

Tags
ListView
Asked by
Daniel
Top achievements
Rank 1
Silver
Bronze
Answers by
Lance | Manager Technical Support
Telerik team
Share this question
or