Set Group Header Toggle control based on Items in Group

Hi  


I am trying to get a Toggle Control in the Group Header Template to update to reflect if all Items with in a group are selected or not,

Image_5615_1756725187655


<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

             x:Class="HazMat.Clients.UI.Pages.HazMat.TestPage"

             xmlns:local="clr-namespace:HazMat.Clients.UI;assembly=HazMat.Clients.UI"

             xmlns:sfListView="clr-namespace:Syncfusion.Maui.ListView;assembly=Syncfusion.Maui.ListView"

             xmlns:i18n="clr-namespace:HazMat.Clients.Portable;assembly=HazMat.Clients.Portable"

             Title="Test"

             NavigationPage.BackButtonTitle="Back" xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls" ios:Page.UseSafeArea="true">

    <sfListView:SfListView x:Name="listView"

         ItemsSource="{Binding StorageUnitsToAdd}"

         AutoFitMode="DynamicHeight"

         ItemSpacing="5"

         SelectionMode="None"

         AllowGroupExpandCollapse="True"

         AllowSwiping="False">

        <sfListView:SfListView.GroupHeaderTemplate>

            <DataTemplate>

                <ViewCell x:Name="{Binding Key}">

                    <StackLayout Orientation="Horizontal" Padding="5" Grid.Row="1">

                        <Label Text="{Binding Key}" VerticalOptions="Center" ></Label>

                        <Switch x:Name="selectAll" IsEnabled="{Binding IsNotBusy}" Toggled="groupSelectedChanged"></Switch>

                    </StackLayout>

                </ViewCell>

            </DataTemplate>

        </sfListView:SfListView.GroupHeaderTemplate>

        <sfListView:SfListView.ItemTemplate>

            <DataTemplate>

                <ViewCell>

                    <StackLayout Orientation="Horizontal" Padding="5" Grid.Row="1">

                        <Label Text="{Binding ID}" VerticalOptions="Center" ></Label>

                        <Switch x:Name="selectAll" IsEnabled="{Binding IsNotBusy}" Toggled="OnSelectedChanged" IsToggled="{Binding IsMoving,Mode=TwoWay}"></Switch>

                    </StackLayout>

                </ViewCell>

            </DataTemplate>

        </sfListView:SfListView.ItemTemplate>

    </sfListView:SfListView>

</ContentPage>


using Switch = Microsoft.Maui.Controls.Switch;

using Syncfusion.Maui.DataSource;

using Syncfusion.Maui.Data;

using Syncfusion.Maui.ListView;

using Syncfusion.Maui.ListView.Helpers;

using System.Collections.ObjectModel;

using System.ComponentModel;

using CommunityToolkit.Mvvm.ComponentModel;


namespace HazMat.Clients.UI.Pages.HazMat

{

    public class StorageUnit : ObservableObject, INotifyPropertyChanged

    {

        public string Group { get; set; }

        public string ID { get; set; }

        public bool IsMoving { get; set; }

    }


    public class TestViewModel : ObservableObject

    {

        public bool IsBusy { get; set; } = false;


        public ObservableCollection<StorageUnit> StorageUnitsToAdd { get; set; } = new ObservableCollection<StorageUnit>();


        public TestViewModel() : base()

        {


            StorageUnitsToAdd = new ObservableCollection<StorageUnit>() {

                    new StorageUnit{Group = "Group 1", ID = "101"},

                    new StorageUnit{Group = "Group 1", ID = "102"},

                    new StorageUnit{Group = "Group 1", ID = "103"},

                    new StorageUnit{Group = "Group 2", ID = "201"},

                    new StorageUnit{Group = "Group 2", ID = "202"},

                    new StorageUnit{Group = "Group 2", ID = "203"}

                };

        }

    }

    public partial class TestPage : ContentPage

    {

        TestViewModel vm;

        public TestPage()

        {

            InitializeComponent();

            BindingContext = vm = new TestViewModel();



            listView.DataSource.GroupDescriptors.Add(new GroupDescriptor()

            {

                PropertyName = "Group",

                KeySelector = (object obj) =>

                {

                    var item = (obj as StorageUnit);

                    return item.Group;

                }

            });

        }


        void groupSelectedChanged(object s, EventArgs e)

        {

            try

            {

                Switch groupSwitch = (Switch)s;

                var groupResult = groupSwitch.BindingContext as Syncfusion.Maui.DataSource.Extensions.GroupResult;


                if (groupResult == null)

                    return;

                var items = groupResult.Items.ToList<StorageUnit>().ToList();


                foreach(var item in items)

                {

                    (item as StorageUnit).IsMoving = groupSwitch.IsToggled;

                }



                this.RefreshGroupHeader(groupResult);

                listView.RefreshView();


            }

            finally

            {

                IsBusy = false;

            }

        }


        private void RefreshGroupHeader(Syncfusion.Maui.DataSource.Extensions.GroupResult group)

        {

            foreach (var item in listView.GetVisualContainer().Children)

            {

                if (item is ListViewGroupHeaderItem &&

                    (item as ListViewGroupHeaderItem)!.BindingContext == group)

                {

                    (item as ListViewGroupHeaderItem).BindingContext = null;

                    (item as ListViewGroupHeaderItem).Content.BindingContext = null;

                }

            }

        }



        void OnSelectedChanged(object s,EventArgs e)

        {

            try

            {


                IsBusy = true;

                Switch thisSwitch = (Switch)s;


                if (thisSwitch.BindingContext == null)

                {

                    return;

                }


                StorageUnit unit = (StorageUnit)thisSwitch.BindingContext;


                var group = listView.DataSource.Groups.Where(g => g.Key == unit.Group).FirstOrDefault();

                if(group !=null)

                {

                    var groupItems = group.Items.ToList<StorageUnit>();

                    if(groupItems.All(u=> u.IsMoving))

                    {

                        //All Items are selected Set Group Toggle IsToggled = true

                    }

                    else

                    {

                        //All Items are selected Set Group Toggle IsToggled = false

                    }

                }

            }

            finally

            {

                IsBusy = false;

            }

        }

    }

}







1 Reply

AP Abinesh Palanisamy Syncfusion Team September 2, 2025 11:50 AM UTC

Hi ,
 
We have validated your code snippet of "GroupHeaderTemplate" where you have used to bind the property (IsNotBusy) of business object , to update toggle state of Switch control. We would like to let you know that binding context of GroupHeaderItem will be "GroupResult" object which is created/generated in ListView source, so you can't bind your own Model/ViewModel properties in GroupHeaderTemplate.
To meet the requirement of syncing the group header switch with the selection state of its items, we implemented a solution using event handlers in the code-behind. When the group header switch is toggled (groupSelectedChanged), we manually update the "IsMoving" property of all items in that group.
Similarly, when an individual item switch is toggled (OnSelectedChanged), we check whether all items in the group are selected. If they are, we update the group header switch accordingly using the UpdateGroupHeaderToggle method.
To achieve this, we traverse the visual tree of the ListView to locate the specific Switch control inside the group header and directly set its IsToggled property. This ensures the group header switch accurately reflects the selection status of its items.
We have included a sample project and a video demo to showcase that your requirement has been successfully achieved.
If you have any further requirements, please feel free to let us know. We’ll be happy to assist.
Regards,
Abinesh P

Attachment: ListView_Grouping_5b1b5db7.zip

Loader.
Up arrow icon