hokkos
hokkos

Reputation: 499

How to have empty groups in a DataGrid in WPF?

I've got a DataGrid in WPF with groups based on a property, but I wan't to have some groups present even when there is no corresponding item.

My code is base on that but with the DataGrid it doesn't work.

<Window
x:Class="EmptyGroups.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Servers by cluster"
WindowStartupLocation="CenterScreen">

<DockPanel>

    <WrapPanel DockPanel.Dock="Top" Background="BlanchedAlmond">
        <Label Content="Cluster name:" Margin="10"/>
        <TextBox x:Name="NewClusterName" Text="type new cluster name here" MinWidth="50" BorderThickness="1" Margin="10"/>
        <Button Content="Add cluster" Click="AddNewCluster_Click" Margin="10"/>
    </WrapPanel>

    <ListView x:Name="ServersList">

        <ListView.GroupStyle>
            <GroupStyle HidesIfEmpty="False">
                <GroupStyle.ContainerStyle>
                    <Style TargetType="GroupItem">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="GroupItem">
                                    <Expander IsExpanded="True">
                                        <Expander.Header>
                                            <TextBlock TextWrapping="Wrap" Margin="0,10,0,5" >
                                                <Bold><TextBlock Text="{Binding Name}"/></Bold> (<TextBlock Text="{Binding ItemCount}"/> servers)
                                            </TextBlock>
                                        </Expander.Header>
                                        <ItemsPresenter/>
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </ListView.GroupStyle>

        <ListView.View>
            <GridView>
                <GridViewColumn Header="Server" DisplayMemberBinding="{Binding Name}"/>
                <GridViewColumn Header="Cluster" DisplayMemberBinding="{Binding Cluster.Name}"/>
            </GridView>
        </ListView.View>
    </ListView>

    <DataGrid Name="ServersGrid" AutoGenerateColumns="False" IsReadOnly="True">
        <DataGrid.GroupStyle>
            <GroupStyle HidesIfEmpty="False">
                <GroupStyle.Panel>
                    <ItemsPanelTemplate>
                        <DataGridRowsPresenter/>
                    </ItemsPanelTemplate>
                </GroupStyle.Panel>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <TextBlock Text="" Width="20" />
                            <TextBlock Text="{Binding Path=Name}"/>
                        </DockPanel>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </DataGrid.GroupStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header="ServerGrid" Binding="{Binding Name}" />
            <DataGridTextColumn Header="ClusterGrid" Binding="{Binding Cluster.Name}"/>
        </DataGrid.Columns>
    </DataGrid>
</DockPanel>

And Windows1.xaml.cs :

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Data;

namespace EmptyGroups
{
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        var clusters = new[]
        {
            new Cluster { Name = "Front end" },
            new Cluster { Name = "Middle end" },
            new Cluster { Name = "Back end" },
        };

        var collectionView = new ListCollectionView(new[]
        {
            new Server { Cluster = clusters[0], Name = "webshop1" },
            new Server { Cluster = clusters[0], Name = "webshop2" },
            new Server { Cluster = clusters[0], Name = "webshop3" },
            new Server { Cluster = clusters[0], Name = "webshop4" },
            new Server { Cluster = clusters[0], Name = "webshop5" },
            new Server { Cluster = clusters[0], Name = "webshop6" },
            new Server { Cluster = clusters[2], Name = "sql1" },
            new Server { Cluster = clusters[2], Name = "sql2" },
        });

        var groupDescription = new PropertyGroupDescription("Cluster.Name");

        // this foreach must at least add clusters that can't be
        // derived from items - i.e. groups with no items in them
        foreach (var cluster in clusters)
            groupDescription.GroupNames.Add(cluster.Name);

        collectionView.GroupDescriptions.Add(groupDescription);
        ServersList.ItemsSource = collectionView;
        ServersGrid.ItemsSource = collectionView;
        Clusters = groupDescription.GroupNames;
    }

    readonly ObservableCollection<object> Clusters;

    void AddNewCluster_Click(object sender, RoutedEventArgs e)
    {
        Clusters.Add(NewClusterName.Text);
    }
}

class Cluster
{
    public string Name { get; set; }
}

class Server
{
    public Cluster Cluster { get; set; }
    public string Name { get; set; }
}
}

After 6 add the DataGrid stop to show all the empty groups. Thanks.

Upvotes: 3

Views: 1845

Answers (1)

hokkos
hokkos

Reputation: 499

Following a question, I answer it myself. Due to a bug in WPF DataGrid there can't be more groups than items, so we add a ghost item for every group present or not and set their Visibility as Collapsed.

Upvotes: 1

Related Questions