Nested expander control in datagrid

Saiyed Wahidunnisa 21 Reputation points
2021-11-01T17:35:16.88+00:00

I want to display nested groups in a datagrid.
Currently one level of grouping is displayed with the help of expander control.

145592-image.png

Groups are identified with the help of tag "ModuleTag"

Displayed on UI like this
145601-image.png

Now I want to add sub groups inside that group which should be displayed using expander.

<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Items[0].IsModuleStartTag}" Value="True">
<Setter Property="Template" Value="{StaticResource ExpanderControlTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Items[0].IsModuleStartTag}" Value="False">
<Setter Property="Template" Value="{StaticResource NonExpanderControlTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>

<ControlTemplate TargetType="{x:Type GroupItem}" x:Key="NonExpanderControlTemplate">
<StackPanel HorizontalAlignment="Stretch">
<ItemsPresenter/>
</StackPanel>
</ControlTemplate>
<ControlTemplate TargetType="{x:Type GroupItem}" x:Key="ExpanderControlTemplate">
<Grid Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}">
<Expander x:Name="GroupExapnder" IsExpanded="False" Style="{StaticResource ResourceKey=stylee}">
<ItemsPresenter/>
</Expander>
<TextBlock x:Name="ModuleHeader" Text="{Binding Items[0].ModuleDetails}" Width="{Binding Path=ActualWidth, ElementName=GroupExapnder}" Padding="180,5,0,0" Margin="60,0,0,0" HorizontalAlignment="Center"
VerticalAlignment="Top" Height="20" Foreground="Black" FontWeight="SemiBold" MouseDown="ModuleHeader_MouseDown" MaxWidth="1000" MouseMove="TextBlock_MouseMove" MouseLeave="ModuleHeader_MouseLeave"/>
</Grid>
</ControlTemplate>

Developer technologies | Windows Presentation Foundation
Developer technologies | XAML
Developer technologies | XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
0 comments No comments
{count} votes

Answer accepted by question author
  1. Hui Liu-MSFT 48,706 Reputation points Microsoft External Staff
    2021-11-02T03:25:03.67+00:00

    You could try to refer to the code of the document.
    I modified the <!-- style of the group under the top level--> part of the sample code to the following code. And the result is as follows, you can check if it works.

    <!-- Style for groups under the top level. -->  
        <GroupStyle>  
                            <GroupStyle.ContainerStyle>  
                                <Style TargetType="{x:Type GroupItem}">  
                                    <Setter Property="Margin" Value=" 0,0,0,5"/>  
                                    <Setter Property="Template">  
                                        <Setter.Value>  
                                            <ControlTemplate TargetType="{x:Type GroupItem}">  
                                                <Expander IsEnabled="True" Background="LightBlue" >  
                                                    <Expander.Header>  
                                                        <DockPanel>  
                                                            <TextBlock Text="{Binding Path=Name, Converter={StaticResource completeConverter}}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>  
                                                            <TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>  
                                                        </DockPanel>  
                                                    </Expander.Header>  
                                                    <Expander.Content>  
                                                        <ItemsPresenter/>  
                                                    </Expander.Content>  
                                                </Expander>  
                                            </ControlTemplate>  
                                        </Setter.Value>  
                                    </Setter>  
                                </Style>  
                            </GroupStyle.ContainerStyle>  
                            <!--<GroupStyle.HeaderTemplate>  
                                <DataTemplate>  
                                    <DockPanel Background="LightBlue">  
                                        <TextBlock Text="{Binding Path=Name, Converter={StaticResource completeConverter}}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>  
                                        <TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>  
                                    </DockPanel>  
                                </DataTemplate>  
                            </GroupStyle.HeaderTemplate>-->  
                        </GroupStyle>  
    

    The picture of result:
    145588-image.png

    Update

    You could try to refer to the following method.
    First set Style.Resource to add an ungrouped ControlTemplate. Then when ItemCount=1, bind ControlTemplate through DataTrigger to set no grouping.

    <Window.Resources>  
            <local:CompleteConverter x:Key="completeConverter" />  
            <local:Tasks x:Key="tasks" />  
            <CollectionViewSource x:Key="cvsTasks" Source="{StaticResource tasks}"  >  
                <CollectionViewSource.GroupDescriptions>  
                    <PropertyGroupDescription PropertyName="ProjectName"/>  
                    <PropertyGroupDescription PropertyName="Complete"/>  
                </CollectionViewSource.GroupDescriptions>  
            </CollectionViewSource>  
        </Window.Resources>  
        <Grid>  
            <DataGrid x:Name="dataGrid1"  AutoGenerateColumns="False"  
                       ItemsSource="{Binding Source={StaticResource cvsTasks}}">  
                <DataGrid.GroupStyle>  
                      
                    <GroupStyle>  
      
                        <GroupStyle.ContainerStyle>  
                            <Style TargetType="{x:Type GroupItem}">  
                                <Style.Resources>  
                                    <ControlTemplate x:Key="notgroup" TargetType="{x:Type GroupItem}">  
                                        <ItemsPresenter />  
                                    </ControlTemplate>  
                                </Style.Resources>  
                                <Setter Property="Template">  
                                    <Setter.Value>  
                                        <ControlTemplate  x:Name="group" TargetType="{x:Type GroupItem}">  
                                            <Expander IsExpanded="True" Background="#FF112255" BorderBrush="#FF002255" Foreground="#FFEEEEEE" BorderThickness="1,1,1,5">  
                                                <Expander.Header>  
                                                    <DockPanel>  
                                                        <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>  
                                                        <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>  
                                                    </DockPanel>  
                                                </Expander.Header>  
                                                <Expander.Content>  
                                                    <ItemsPresenter/>  
                                                </Expander.Content>  
                                            </Expander>  
                                        </ControlTemplate>  
                                    </Setter.Value>  
                                </Setter>  
                                <Setter Property="Margin" Value="0,0,0,5"/>  
                                <Style.Triggers>  
                                    <DataTrigger Binding="{Binding ItemCount}" Value="1">  
                                        <Setter Property="Template" Value="{StaticResource notgroup }"/>  
                                    </DataTrigger>  
                                </Style.Triggers>  
                            </Style>  
                        </GroupStyle.ContainerStyle>  
                    </GroupStyle>  
                    <GroupStyle>  
                        <GroupStyle.ContainerStyle>  
                            <Style TargetType="{x:Type GroupItem}">  
                                <Style.Resources>  
                                    <ControlTemplate x:Key="notgroup1" TargetType="{x:Type GroupItem}">  
                                        <ItemsPresenter />  
                                    </ControlTemplate>  
                                </Style.Resources>  
                                <Setter Property="Margin" Value=" 0,0,0,5"/>  
                                <Setter Property="Template">  
                                    <Setter.Value>  
                                        <ControlTemplate TargetType="{x:Type GroupItem}">  
                                            <Expander IsEnabled="True" Background="LightBlue" >  
                                                <Expander.Header>  
                                                    <DockPanel>  
                                                        <TextBlock Text="{Binding Path=Name, Converter={StaticResource completeConverter}}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>  
                                                        <TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>  
                                                    </DockPanel>  
                                                </Expander.Header>  
                                                <Expander.Content>  
                                                    <ItemsPresenter/>  
                                                </Expander.Content>  
                                            </Expander>  
                                        </ControlTemplate>  
                                    </Setter.Value>  
                                </Setter>  
                                <Style.Triggers>  
                                    <DataTrigger Binding="{Binding ItemCount}" Value="1">  
                                        <Setter Property="Template" Value="{StaticResource notgroup1 }"/>  
                                    </DataTrigger>  
                                </Style.Triggers>  
                            </Style>  
                        </GroupStyle.ContainerStyle>  
                    </GroupStyle>  
                </DataGrid.GroupStyle>  
                <DataGrid.Columns>  
                    <DataGridTextColumn Header="ProjectName" Binding="{Binding ProjectName}" />  
                    <DataGridTextColumn Header="TaskName" Binding="{Binding TaskName}" />  
                    <DataGridTextColumn Header="DueDate" Binding="{Binding DueDate}" />  
                    <DataGridTextColumn Header="Complete" Binding="{Binding Complete}" />  
                </DataGrid.Columns>  
            </DataGrid>  
        </Grid>  
    

    The code of xaml.cs :
    For testing, I modified the MainWindow() method to the following code.

    public MainWindow()  
        {  
          InitializeComponent();  
          Tasks _tasks = (Tasks)this.Resources["tasks"];  
            _tasks.Add(new Task(){ ProjectName = "Project1 ", TaskName = "Task1 " , DueDate=DateTime.Now , Complete = true });  
            _tasks.Add(new Task(){ ProjectName = "Project3 ", TaskName = "Task2 " , DueDate = DateTime.Now, Complete = true});  
            _tasks.Add(new Task(){ ProjectName = "Project2 ", TaskName = "Task3 " , DueDate = DateTime.Now, Complete = false });  
            _tasks.Add(new Task(){ ProjectName = "Project4 ", TaskName = "Task4 " , DueDate = DateTime.Now, Complete = true  });  
            _tasks.Add(new Task(){ ProjectName = "Project5 ", TaskName = "Task7 " , DueDate = DateTime.Now, Complete = false});  
            _tasks.Add(new Task(){ ProjectName = "Project5 ", TaskName = "Task3 " , DueDate = DateTime.Now, Complete = false });  
            _tasks.Add(new Task(){ ProjectName = "Project5 ", TaskName = "Task3 " , DueDate = DateTime.Now, Complete = true });  
            _tasks.Add(new Task(){ ProjectName = "Project5 ", TaskName = "Task3 " , DueDate = DateTime.Now, Complete = true });  
            _tasks.Add(new Task(){ ProjectName = "Project6 ", TaskName = "Task8 " , DueDate = DateTime.Now, Complete = true  });  
            
        }  
    

    The picture of result:

    145965-image.png


    If the answer is the right solution, please click Accept Answer and kindly upvote it. If you have extra questions about this answer, please click Comment.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


2 additional answers

Sort by: Most helpful
  1. Saiyed Wahidunnisa 21 Reputation points
    2021-11-01T20:17:37.567+00:00
    0 comments No comments

  2. Saiyed Wahidunnisa 21 Reputation points
    2021-11-02T07:58:35.56+00:00

    Hi @Hui Liu-MSFT
    Thanks for the response. I have tried this approach as well.
    I have one issue with this
    Just like in the screenshot you see grouped(expander) and ungrouped(normal lines) are placed together in a sequence(what ever comes from the data source. ) Sequence should not change. Data coming will already be in grouped sequence. (As you can see from the XML screenshot).
    Now I want the same behaviour inside the expander as well. Meaning it can have ungrouped lines then some grouped lines(expander inside and expander) and then some ungrouped lines.

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.