Drag and Drop grouping in Datagrid

Most 3rd party components have a datagrid where you can a drag column header to the area above the grid to group the data. Here is one way to do the same with a regular datagrid

I am using SL4 and the latest Silverlight toolkit.
Here is my XAML, a Grid with 2 rows. In row 0 – a listbox where we drop the dragged columnheaders, in row 1 a Datagrid with columns defined

<Grid x:Name=”LayoutRoot” Background=”White” Height=”500″  Width=”400″>
        <Grid.RowDefinitions>
            <RowDefinition Height=”40″/>
            <RowDefinition Height=”*”/>           
        </Grid.RowDefinitions>
        <Grid  Grid.Row=”0″>
            <toolkit:ListBoxDragDropTarget AllowDrop=”True” Drop=”PanelDragDropTarget_Drop” Background=”#FFA74F4F”
                                           HorizontalContentAlignment=”Stretch” VerticalContentAlignment=”Stretch”>
                <ListBox x:Name=”list1″>
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation=”Horizontal”/>
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Border BorderBrush=”Black” BorderThickness=”1″ >
                            <StackPanel Orientation=”Horizontal”  VerticalAlignment=”Center”>
                                <TextBlock Text=”{Binding}” Height=”20″/>
                                <Button Content=”x” Height=”20″  Margin=”5,0,0,0″ Click=”btn_Click” VerticalContentAlignment=”Top” />
                            </StackPanel>
                            </Border>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </toolkit:ListBoxDragDropTarget>        
        </Grid>
        <my:DataGrid x:Name=”datagrid1″ Grid.Row=”1″ AutoGenerateColumns=”False” Style=”{StaticResource DataGridStyle1}”>
            <my:DataGrid.Columns>
                <my:DataGridTextColumn Header=”Name”  Binding=”{Binding Name}”/>
                <my:DataGridTextColumn Header=”Title”  Binding=”{Binding Title}”/>
                <my:DataGridTextColumn Header=”City”  Binding=”{Binding City}”/>
                <my:DataGridTextColumn Header=”Country”  Binding=”{Binding Country}”/>
            </my:DataGrid.Columns>
        </my:DataGrid>       
    </Grid>

Next we need to allow the DataGridColumnHeaders to be draggable, so I grabbed the template of the datagrid, wrapped DataGridColumnHeadersPresenter in a PanelDragDropTarget like below. This is the only change in the template

<toolkit:PanelDragDropTarget Grid.Column=”1″ HorizontalContentAlignment=”Stretch”
 VerticalContentAlignment=”Stretch” AllowedSourceEffects=”Copy”>
 <sdk:DataGridColumnHeadersPresenter x:Name=”ColumnHeadersPresenter” AllowDrop=”True”   />
</toolkit:PanelDragDropTarget>

we handle the drop event to add the dragged item to the list of items we grouped with allowing the user to ungroup by clicking the button
 private void PanelDragDropTarget_Drop(object sender, Microsoft.Windows.DragEventArgs e)
        {
            // Retrieve the dropped data in the first available format.
            object data = e.Data.GetData(e.Data.GetFormats()[0]);
            DataGridColumnHeader dgch = ((data as ItemDragEventArgs).Data as SelectionCollection)[0].Item as DataGridColumnHeader;            
            list1.Items.Add(dgch.Content.ToString());           
            UpdateGroups();
        }

        void btn_Click(object sender, RoutedEventArgs e)
        {
            list1.Items.Remove((sender as Button).DataContext);
            UpdateGroups();
        }

        private void UpdateGroups()
        {
            if (pcv.GroupDescriptions != null)
                pcv.GroupDescriptions.Clear();

            list1.Items.ToList().ForEach(x =>
            {
                pcv.GroupDescriptions.Add(new PropertyGroupDescription { PropertyName = x.ToString() });
            }
            );
        }

you can download the code from here

Advertisements

10 thoughts on “Drag and Drop grouping in Datagrid

  1. Hi, I have a simple silverligth 3 datagrid, with 1 GroupDescriptions set (“grouping”, cat1,cat2,cat3), so I have the grouping part working, I have also used the same method as you have shown above to get the select all checkbox in the header row. I would like to try and add another check box in the grouping header as well as in the column header, thus allowing the user to click select all for one grouping. e.g. the column header check box will tick all cat 1,2 and 3 items. The groupiong checkbox when ticked should tick e.g just cat1 items. Is this possible or should i start looking at 3rd party controls

    1. Hi,
      If I undertand correctly, you want to have a checkbox in group header to select all the items in the selected group. Do you have a sample solution you can send me, I can take a look at?

  2. I am using Datagrid with in Datagrid with 4 levels, I’m facing row height when collapsing 2nd or 3rd or 4th level can any help me on this.

  3. How Can I have the CheckBox at Group Level (Country) which if checked should check all the individual row checkboxes under that group

  4. Has anyone noticed that this solution has the adverse side effect of re-ordering columns when moving a ColumnHeader to the ListBox. I’m not sure if this was the behavior when I first started exploring this solution or a side-affect from something I’ve done. Grouping works as expected but the columns reorder as if I had dropped the ColumnHeader on the ColumnHeadersPresenter.

    Seems like Column should have a simple visibility property that I can set to hide the column(s) that I’m currently grouping by … but I’ll explore this more if no one here can correct my fumbled ways…

    1. Hi,
      I did not notice it myself, but that would be probable. I did not have a chance to check my solution if it is exhibiting the same behavior.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s