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