BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Data Display Controls - DataGrid - Selection

The one hundred and thirteenth part of the Windows Presentation Foundation Fundamentals tutorial further investigates the DataGrid control. This instalment looks at the selection capabilities of the control.

Detecting Selections

Once the user has selected cells or rows in a data grid, you might wish to determine which items are selected programmatically. You can do this by reading the DataGrid class's SelectedCells property. This returns a list of DataGridCellInfo values, with one for each selection. Each object includes properties that you can use to find the location of the selected cell and its content.

The following key properties can be interrogated:

  • Column. Returns the column containing the selected cell. You can find details of the column using the properties that we've seen in earlier articles. The returned value is a DataGridColumn object. This type includes the GetCellContent method, which returns the content of the selected cell.
  • Item. Returns the item in the data bound collection that is represented by the row containing the selected cell.
  • IsValue. This Boolean property returns true when the selected cell contains valid information. If the value is unset, or is null, the property returns false.

To demonstrate how the selections can be obtained, we'll add a button to the window. When the button is clicked we'll show the details of the selected cells in a message box.

To begin, replace all of the window's XAML with the following code, to add the button in a new Grid cell.

<Window x:Class="DataGridColumnsDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
        Title="Planets of the Solar System"
        Height="275"
        Width="450">
				
    <Window.Resources>
        <CollectionViewSource x:Key="SortedPlanets" Source="{Binding}">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Name" Direction="Ascending" />
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="22"/>
        </Grid.RowDefinitions>

        <DataGrid Name="SampleGrid"
                  ItemsSource="{Binding Source={StaticResource SortedPlanets}}"
                  AutoGenerateColumns="False" Hyperlink.Click="DataGrid_Click"
                  SelectionMode="Extended" SelectionUnit="CellOrRowHeader">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" Header="Planet" Width="80"
                                    Foreground="Blue" FontWeight="Bold"
                                    CanUserReorder="False"/>
                <DataGridCheckBoxColumn Binding="{Binding HasRings}" Header="Rings?"
                                        Width="50" CanUserResize="False"/>
                <DataGridCheckBoxColumn Binding="{Binding GlobalMagneticField}"
                                        Width="140" Header="Global Magnetic Field?"
                                        IsThreeState="True"/>
                <DataGridComboBoxColumn Header="Category" Width="80"
                                        SelectedItemBinding="{Binding Category}">
                    <DataGridComboBoxColumn.ItemsSource>
                        <CompositeCollection>
                            <sys:String>Terrestrial</sys:String>
                            <sys:String>Gas Giant</sys:String>
                            <sys:String>Ice Giant</sys:String>
                            <sys:String>Dwarf Planet</sys:String>
                        </CompositeCollection>
                    </DataGridComboBoxColumn.ItemsSource>
                </DataGridComboBoxColumn>
                <DataGridHyperlinkColumn Binding="{Binding MoreInfoUri}" Header="More"
                                         Width="80" ContentBinding="{Binding Name}"
                    SortMemberPath="Name" />
                <DataGridTemplateColumn Header="Moons" Width="50" SortMemberPath="Moons">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Moons}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Text="{Binding Moons}" />
                                <ScrollBar Grid.Column="1" Minimum="0" Maximum="100"
                                           SmallChange="1" Orientation="Vertical"
                                           Value="{Binding Moons,
                                                   UpdateSourceTrigger=PropertyChanged}"
                                           RenderTransformOrigin="0.5,0.5">
                                    <ScrollBar.RenderTransform>
                                        <ScaleTransform ScaleY="-1"/>
                                    </ScrollBar.RenderTransform>
                                </ScrollBar>
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

        <Button Grid.Row="1" Width="100" HorizontalAlignment="Right"
                Click="Info_Click">Show Selection</Button>
    </Grid>
</Window>

We can now add the Click event code for the button behind the window. Add the following code:

private void Info_Click(object sender, RoutedEventArgs e)
{
    var selectedItems = SampleGrid.SelectedCells.Select(c => CellData(c));
    string msg = selectedItems.Aggregate((c, n) => c + Environment.NewLine + n);
    MessageBox.Show(msg);
}
				
private string CellData(DataGridCellInfo cell)
{
    return string.Format("{0}/{1} = {2}"
        , ((Planet)cell.Item).Name, cell.Column.Header
        , cell.Column.GetCellContent(cell.Item));
}

When the button is clicked, the first method gets the selected cells and produces a string representing each one. It uses the Aggregate method to combine the strings before showing them.

The CellData method creates the strings from three pieces of DataGridCellInfo information. To identify the column, we read the Column property and extract its Header, as shown at the top of the grid. The row of the selected cell is identified by reading Item, which returns the correct Planet object. The string.Format method includes the Name property from that Planet.

The final text added into the string is the content of the selected cell. Note how the GetCellContent method of the column is used to obtain this, with the Planet passed to the parameter of the method to identify which object contains the underlying data. The content will not be a plain string. It will contain the details of the controls that are present within the cell. For example, for the Name column the method will return a TextBlock.

Run the program, make some selections and click the button to see the results.

Selecting and Deselecting All Cells

The final two members that we'll consider in this article allow you to programmatically select or deselect every cell within the DataGrid. To add every cell to the current selection, call the SelectAllCells method. To deselect every cell, you can call UnselectAllCells.

To demonstrate, let's add two more buttons to the window. Add the following XAML beneath the existing button:

<Button Grid.Row="1" Width="100" HorizontalAlignment="Right"
        Margin="0 0 200 0" Click="SelectAll_Click">Select All</Button>
<Button Grid.Row="1" Width="100" HorizontalAlignment="Right"
        Margin="0 0 100 0" Click="UnselectAll_Click">Unselect All</Button>

Next, add the code to select and deselect the cells in response to the two Click events:

private void SelectAll_Click(object sender, RoutedEventArgs e)
{
    SampleGrid.SelectAllCells();
}

private void UnselectAll_Click(object sender, RoutedEventArgs e)
{
    SampleGrid.UnselectAllCells();
}

You can now run the program and click the buttons to see the effects of the two methods.

20 November 2014