Selection in WinUI DataGrid

3 Jun 202224 minutes to read

SfDataGrid allows you to select one or more rows or cells. For selecting specific row or group of rows you have to set SelectionUnit as Row and for selecting a specific cell or group of cells you have to set SelectionUnit as Cell or Any. In Any option you can select the row by clicking on row header.

Current Cell Navigation

Keyboard navigation through the cells and rows is determined based on the NavigationMode property. NavigationMode.Cell allows you to navigate between the cells in a row as well as between rows. NavigationMode.Row allows you to navigate only between rows. It is not possible to set NavigationMode.Row when cell selection is enabled (SelectionUnit is Cell or Any).

Selection Modes

The SelectionUnit and SelectionMode properties together define the behavior of selection in SfDataGrid. If the SelectionMode is Single, you can able to select single row or cell, and if the SelectionMode is Extended or Multiple, you can able to select multiple rows or cell, and if you want to disable the selection you need to set SelectionMode as None.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       SelectionUnit="Row"
                       NavigationMode="Cell"
                       SelectionMode="Single"
                       ItemsSource="{Binding Orders}">

Single Row Selection in WinUI DataGrid

Disable selection for rows and columns

You can disable selection and navigation on particular column by setting GridColumn.AllowFocus property. You can disable selection on particular row or cell or column by handling CurrentCellActivating event.

NOTE

It is not possible to select header rows, table summary rows, unbound rows which are above the table summary row when it’s placed in top and the unbound rows which are below table summary rows when it’s placed in bottom of SfDataGrid.

Multiple Row or Cell Selection

The SfDataGrid allows you to select multiple rows or cells by setting SelectionMode property as Extended or Multiple, where you can select multiple rows or cells by dragging the mouse on SfDataGrid and also using the key modifiers.

While using Extended, you can select multiple rows or cells by pressing the key modifiers Ctrl and Shift.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       SelectionUnit="Cell"
                       NavigationMode="Cell"
                       SelectionMode="Extended"
                       ItemsSource="{Binding Orders}">

Extended Cell Selection in WinUI DataGrid

NOTE

When the SelectionMode as Multiple, you can select or deselect multiple rows and cells by clicking the respective cell or row. Also in multiple selection pressing navigation keys will move only the current cell and you can select or deselect by pressing space key.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       SelectionUnit="Cell"
                       NavigationMode="Cell"
                       SelectionMode="Multiple"
                       ItemsSource="{Binding Orders}">

Multiple Cell Selection in WinUI DataGrid

Get Selected Rows and Cells

The SelectedItem property returns the data object of the selected row and the SelectedIndex property returns the index of the SelectedItem in SfDataGrid. SelectedItem denotes the first selected row in multiple selection.

The CurrentItem returns the data object that currently has the focus and the CurrentColumn denotes the GridColumn that currently has the focus. The CurrentCellInfo returns an instance GridCellInfo which contains the information about the cell that currently has the focus.

Row Selection

You can gets all the selected records through SelectedItems property and you can also get all selected rows information through SfDataGrid.SelectionController.SelectedRows which is the collection of GridRowInfo.

Cell Selection

You can get all selected cells information through SfDataGrid.SelectionController.SelectedCells property which is the collection of GridSelectedCellsInfo.

You can get the selected cells as GridCellInfo collection by using GetSelectedCells method.

List<GridCellInfo> selectedCells = this.sfDataGrid.GetSelectedCells();

CurrentItem vs SelectedItem

Both SelectedItem and CurrentItem returns the same data object when there is single cell or row is selected in SfDataGrid. When you have selected more than one rows or cells, the record that had been selected initially is maintained in SelectedItem and the record that currently have focus is maintained in CurrentItem.

Programmatic selection

Process selection using properties

You can select a single row or cell by setting SelectedIndex property.

var recordIndex = this.sfDataGrid.ResolveToRecordIndex(5);
this.sfDataGrid.SelectedIndex = recordIndex;
var recordIndex = this.sfDataGrid.ResolveToRecordIndex(6);
object record = null;
if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
{
    var displayElement = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex];
    if (displayElement is RecordEntry)
        record = ((RecordEntry)displayElement).Data;
}
else
    record = this.sfDataGrid.View.Records[recordIndex].Data;

this.sfDataGrid.SelectedItem = record;

In Row selection, you can select multiple rows by adding data objects to SelectedItems property.

var viewModel = this.sfDataGrid.DataContext as ViewModel;

foreach(var order in viewModel.Orders)
{
    if (order.Country == "Mexico")
        this.sfDataGrid.SelectedItems.Add(order);
}

Programmatic Selection of Records in WinUI DataGrid

Process selection using methods

You can select range of rows through SelectRows method in row selection.

this.sfDataGrid.SelectRows(3, 7);

Programmatic Selection of Records in WinUI DataGrid

You can select a specific cell by using the SelectCell method in cell selection.

object record = null;
var recordIndex = this.sfDataGrid.ResolveToRecordIndex(3);
if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
{
    var displayElement = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex];
    if (displayElement is RecordEntry)
        record = ((RecordEntry)displayElement).Data;
}
else
    record = this.sfDataGrid.View.Records[recordIndex].Data;

var column = this.sfDataGrid.Columns[1];
this.sfDataGrid.SelectCell(record, column);

Programmatic Selection of Cell in WinUI DataGrid

You can select a range of cells through SelectCells method in cell selection.

public MainWindow()
{
    InitializeComponent();
    this.sfDataGrid.Loaded += SfDataGrid_Loaded;
}

private void dataGrid_Loaded(object sender, RoutedEventArgs e)
{
    object firstRecord = null, lastRecord = null;

    var recordIndex1 = this.sfDataGrid.ResolveToRecordIndex(3);
    var recordIndex2 = this.sfDataGrid.ResolveToRecordIndex(7);

    if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
    {
        var displayElement1 = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex1];
        if (displayElement1 is RecordEntry)
            firstRecord = ((RecordEntry)displayElement1).Data;

        var displayElement2 = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex2];
        if (displayElement2 is RecordEntry)
            lastRecord = ((RecordEntry)displayElement2).Data;
    }
    else
    {
        firstRecord = this.sfDataGrid.View.Records[recordIndex1].Data;
        lastRecord = this.sfDataGrid.View.Records[recordIndex2].Data;
    }

    var firstColumn = this.sfDataGrid.Columns[1];
    var lastColumn = this.sfDataGrid.Columns[3];

    this.sfDataGrid.SelectCells(firstRecord, firstColumn, lastRecord, lastColumn);
}

Programmatic Selection of Cells in WinUI DataGrid

You can select all the rows or cells using SelectAll method.

this.sfDataGrid.SelectAll();

Process Current Cell

When you set the CurrentItem to particular record, the CurrentCell will be moved to corresponding record when the SelectionMode is Multiple or Extended and the selection will added to the particular record item when the SelectionMode is Single.

var viewModel = this.sfDataGrid.DataContext as ViewModel;
this.sfDataGrid.CurrentItem = viewModel.Orders.FirstOrDefault(order => order.Country == "Spain");

You can move the CurrentCell to a particular rowColumnIndex by using the MoveCurrentCell method.

this.sfDataGrid.MoveCurrentCell(new RowColumnIndex(3,2), false);

Clear Selection

You can clear the selection by using the ClearSelection method. In Row Selection you can also remove the selection by setting null to SelectedItem or clearing the SelectedItems property.

this.sfDataGrid.SelectionController.ClearSelections(true);

You can clear selection on group of cells by using the UnselectCells method in cell selection.

object firstRecord = null, lastRecord = null;

var recordIndex1 = this.sfDataGrid.ResolveToRecordIndex(3);
var recordIndex2 = this.sfDataGrid.ResolveToRecordIndex(7);

if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
{
    var displayElement1 = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex1];
    if (displayElement1 is RecordEntry)
        firstRecord = ((RecordEntry)displayElement1).Data;

    var displayElement2 = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex2];
    if (displayElement2 is RecordEntry)
        lastRecord = ((RecordEntry)displayElement2).Data;
}
else
{
    firstRecord = this.sfDataGrid.View.Records[recordIndex1].Data;
    lastRecord = this.sfDataGrid.View.Records[recordIndex2].Data;
}

var firstColumn = this.sfDataGrid.Columns[1];
var lastColumn = this.sfDataGrid.Columns[3];
this.sfDataGrid.UnselectCells(firstRecord, firstColumn, lastRecord, lastColumn);

You can clear the selection on particular cell by using the UnSelectCell method in cell selection.

object record = null;
var recordIndex = this.sfDataGrid.ResolveToRecordIndex(5);

if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
{
    var displayElement = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex];
    if (displayElement is RecordEntry)
        record = ((RecordEntry)displayElement).Data;
}
else
    record = this.sfDataGrid.View.Records[recordIndex].Data;

var column = this.sfDataGrid.Columns[2];
this.sfDataGrid.UnselectCell(record, column);

Programmatic Removal of Selection for a Cell in WinUI DataGrid

Selection in Master-Details View

Master-Details View provides support to select one or more rows or cells in DetailsViewDataGrid. You can’t able to maintain the selection in both ParentDataGrid and DetailsViewDataGrid. Selection will be maintained either in ParentDataGrid or in DetailsViewDataGrid.

WinUI DataGrid Selection in Master Details View

Getting SelectedDetailsViewDataGrid

You can get the currently selected DetailsViewDataGrid by using the SelectedDetailsViewGrid property of parent DataGrid.

var detailsViewDataGrid = this.sfDataGrid.SelectedDetailsViewGrid;

For accessing nested level SelectedDetailsViewGrid,

var detailsViewDataGrid = this.sfDataGrid.SelectedDetailsViewGrid.SelectedDetailsViewGrid;

Getting SelectedItem from DetailsViewDataGrid

You can get the selected record of DetailsViewDataGrid by using the SelectedItem property.

var detailsViewDataGrid = this.sfDataGrid.SelectedDetailsViewGrid;
var selectedItem = detailsViewDataGrid.SelectedItem;

You can get the SelectedItem while it’s changed using SelectionChanged event of ViewDefinition.DataGrid.

<dataGrid:GridViewDefinition RelationalColumn="OrderDetails">
    <dataGrid:GridViewDefinition.DataGrid>
        <dataGrid:SfDataGrid x:Name="firstDetailsViewGrid" 
                               SelectionChanged="firstDetailsViewGrid_SelectionChanged">
        </dataGrid:SfDataGrid>
    </dataGrid:GridViewDefinition.DataGrid>
</dataGrid:GridViewDefinition>
firstDetailsViewGrid.SelectionChanged += firstDetailsViewGrid_SelectionChanged;

private void firstDetailsViewGrid_SelectionChanged(object sender, Syncfusion.UI.Xaml.Grid.GridSelectionChangedEventArgs e)
{
    var selectedItem = (e.OriginalSender as DetailsViewDataGrid).SelectedItem;
}

NOTE

You can get the SelectedIndex and SelectedItems also in SelectionChanged event.

Get the CurrentItem of DetailsViewDataGrid

You can get the current record of the DetailsViewDataGrid by using the CurrentItem property.

var detailsViewDataGrid = this.sfDataGrid.SelectedDetailsViewGrid;
var currentItem = detailsViewDataGrid.CurrentItem;

You can get the CurrentItem while it’s changed using SelectionChanged event of ViewDefinition.DataGrid.

<dataGrid:GridViewDefinition RelationalColumn="OrderDetails">
    <dataGrid:GridViewDefinition.DataGrid>
        <dataGrid:SfDataGrid x:Name="firstDetailsViewGrid" 
                               SelectionChanged="firstDetailsViewGrid_SelectionChanged">
        </dataGrid:SfDataGrid>
    </dataGrid:GridViewDefinition.DataGrid>
</dataGrid:GridViewDefinition>
firstDetailsViewGrid.SelectionChanged+=firstDetailsViewGrid_SelectionChanged;

private void firstDetailsViewGrid_SelectionChanged(object sender, Syncfusion.UI.Xaml.Grid.GridSelectionChangedEventArgs e)
{
    var currentItem = (e.OriginalSender as DetailsViewDataGrid).CurrentItem;
}

Get CurrentCell of DetailsViewDataGrid

You can get the CurrentCell of DetailsViewDataGrid by using the SelectedDetailsViewGrid property. You can use different events of ViewDefinition.DataGrid like CurrentCellBeginEdit, CurrentCellActivated to get the CurrentCell.

var currentCell = this.sfDataGrid.SelectedDetailsViewGrid.SelectionController.CurrentCellManager.CurrentCell;

You can get the CurrentCell using CurrentCellBeginEdit event ViewDefinition.DataGrid.

<dataGrid:GridViewDefinition RelationalColumn="OrderDetails">
    <dataGrid:GridViewDefinition.DataGrid>
        <dataGrid:SfDataGrid x:Name="firstLevelNestedGrid"                                                   
                               CurrentCellBeginEdit="firstLevelNestedGrid_CurrentCellBeginEdit">
        </dataGrid:SfDataGrid>
    </dataGrid:GridViewDefinition.DataGrid>
</dataGrid:GridViewDefinition>
this.firstLevelNestedGrid.CurrentCellBeginEdit += firstLevelNestedGrid_CurrentCellBeginEdit;

void firstLevelNestedGrid_CurrentCellBeginEdit(object sender, CurrentCellBeginEditEventArgs e)
{
    var detailsViewDataGrid = e.OriginalSender as DetailsViewDataGrid;
    var currentCell = detailsViewDataGrid.SelectionController.CurrentCellManager.CurrentCell;
}

Programmatic Selection in DetailsViewDataGrid

You can select data objects while loading DetailsViewDataGrid using DetailsViewLoading event.

<dataGrid:SfDataGrid Name="sfDataGrid" 
                       DetailsViewLoading="sfDataGrid_DetailsViewLoading" >
</dataGrid:SfDataGrid>
void sfDataGrid_DetailsViewLoading(object sender, DetailsViewLoadingAndUnloadingEventArgs e)
{
    object record = null;
    var recordIndex = e.DetailsViewDataGrid.ResolveToRecordIndex(2);
    if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
    {
        var displayElement = e.DetailsViewDataGrid.View.TopLevelGroup.DisplayElements[recordIndex];
        if (displayElement is RecordEntry)
            record = ((RecordEntry)displayElement).Data;
    }
    else
        record = e.DetailsViewDataGrid.View.Records[recordIndex].Data;

    e.DetailsViewDataGrid.SelectedItem = record;
}

Programmatically expanding and scrolling DetailsViewDataGrid

You can expand the DetailsViewDataGrid programmatically by calling ExpandDetailsViewAt method by passing the record index.

int parentRowIndex = 2;
var recordIndex = this.sfDataGrid.ResolveToRecordIndex(parentRowIndex);
if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
{
    var displayElement = this.sfDataGrid.View.TopLevelGroup.DisplayElements[recordIndex];
    if (displayElement is RecordEntry)
        if (!((RecordEntry)displayElement).IsExpanded)
            this.sfDataGrid.ExpandDetailsViewAt(recordIndex);
}
else
{
    var record = this.sfDataGrid.View.Records[recordIndex];
    if (!record.IsExpanded)
        this.sfDataGrid.ExpandDetailsViewAt(recordIndex);
}

Customizing the SelectionController for DetailsViewDataGrid

The DetailsViewDataGrid process the selection operations in selection controller. Below are the built-in selection controllers,

You can customize the default row selection behavior by overriding GridSelectionController class and set it to DetailsViewDataGrid.SelectionController.

The below code-snippet explains you about the customization of GridSelectionController class.

this.sfDataGrid.DetailsViewLoading += sfDataGrid_DetailsViewLoading;

void sfDataGrid_DetailsViewLoading(object sender, DetailsViewLoadingAndUnloadingEventArgs e)
{

    if (!(e.DetailsViewDataGrid.SelectionController is GridSelectionControllerExt))
    e.DetailsViewDataGrid.SelectionController = new GridSelectionControllerExt (e.DetailsViewDataGrid);
}
public class GridSelectionControllerExt : GridSelectionController
{      
    public GridSelectionControllerExt(SfDataGrid datagrid)
        : base(datagrid)
    {             
    }
}

Scrolling Rows or Columns

Automatic scrolling on Drag Selection

SfDataGrid will scrolls rows and columns automatically when you try to perform the drag selection like in excel. You can enable or disable AutoScrolling by setting the AutoScroller.AutoScrolling property.

this.sfDataGrid.AutoScroller.AutoScrolling = AutoScrollOrientation.Both;

Scroll to particular RowColumnIndex

You can scroll programmatically to particular cell using ScrollInView method by passing row and column index.

this.sfDataGrid.ScrollInView(new RowColumnIndex(50, 10));

Scroll to SelectedItem

You can scroll programmatically to the SelectedItem using the ScrollInView method.

var rowIndex = this.sfDataGrid.ResolveToRowIndex(this.sfDataGrid.SelectedItem);
var columnIndex = this.sfDataGrid.ResolveToStartColumnIndex();
this.sfDataGrid.ScrollInView(new RowColumnIndex(rowIndex, columnIndex));

Mouse and Keyboard Behaviors

Keyboard Behavior

Key or KeyCombinations Description
DownArrow Moves CurrentCell directly below the active current cell. If the CurrentCell is in last row, pressing DownArrow does nothing.
UpArrow Moves the CurrentCell directly above the active current cell. If the CurrentCell is in first row, pressing UpArrow does nothing.
LeftArrow Moves the current cell to previous to the active current cell. If the CurrentCell is in first cell, pressing LeftArrow does nothing. If the focused row is group header, the group will be collapsed when it is in expanded state.
RightArrow Moves the current cell to next to the active current cell. If the CurrentCell is in last cell, pressing RightArrow does nothing. If the focused row is group header, the group will expanded when it is in collapsed state.
Home / Ctrl + LeftArrow Moves the current cell to the first cell of the current row.
End / Ctrl + RightArrow Moves the current cell to the last cell of the current row.
PageDown The SfDataGrid will be scrolled to next set of rows that are not displayed in view, including the row that are partially displayed and the current cell is set to last row.
PageUp The SfDataGrid will be scrolled to previous set of rows that are not displayed in view, including the row that are partially displayed and the current cell is set to the first row.
Tab Moves the current cell to next to the active current cell. If the active current cell is the last cell of the current row, the focus will moved to first cell of the row next to the current row.If the active current cell is the last cell of the last row, the focus will be moved to next control in the tab order of the parent container.
Shift + Tab Moves the current cell to previous to the active current cell. If the active current cell is the first cell of the current row, the current cell will moved to last cell of the row previous to the current row.If the active current cell is the first cell of the first row, the focus will be moved to previous control in the tab order of the parent container.
Ctrl + DownArrow Moves the current cell to the current column of the last row.
Ctrl + UpArrow Moves the current cell to the current column of the first row.
Ctrl + Home Moves the current cell to the first cell of the first row.
Ctrl + End Moves the current cell to the last cell of the last row.
Enter If the active current cell is in edit mode, the changes will committed and moves the current cell to below the active current cell. If the active current cell is in last row, commits changes only and retains in the same cell.
Ctrl + Enter Commits only the changes when the current cell in edit mode and retains the focus in same cell.
F2 If the

DataGrid.AllowEditing

property is true and the

GridColumn.AllowEditing

property is true for the current column, the current cell enters into edit mode.
Esc If the current cell is in edit mode, reverts the changes that had been done in the current cell. If the underlying source implements the

IEditableObject

, on pressing of Esc key for the second time will cancel the edit mode for entire row.
Delete If the current cell is not in edit mode, the current row will be deleted.
Ctrl + A All rows or cells will be selected.

NOTE

When the NavigationMode is in Row, the RightArrow and LeftArrow only work for grouping headers and the following keys Tab, Shift + Tab, Delete, Home, End will not work.

Shift Key Combinations

When the SelectionMode is set to Extended, you can select multiple rows or cells using the navigation keys along with the Shift key. Before navigation starts, the current cell will be marked as a pressed cell and the selection will be done in all rows or cells between the pressed cell and current cell.

Key Combinations
Shift + DownArrow
Shift + UpArrow
Shift + RightArrow
Shift + LeftArrow
Shift + Home
Shift + End
Shift + PageDown
Shift + PageUp
Shift + Ctrl + DownArrow
Shift + Ctrl + UpArrow
Shift + Ctrl + RightArrow
Shift + Ctrl + LeftArrow
Shift + Ctrl + Home
Shift + Ctrl + End
Shift + Ctrl + PageDown
Shift + Ctrl + PageUp

Mouse Behavior

You can enable/disable the selection when the mouse button is in pressed state by setting the AllowSelectionOnPointerPressed property.

When the SelectionMode is set to Extended, you can select multiple rows or cells by clicking on any cell along with ctrl and Shift key. When you click a cell along with Ctrl key, you can select or deselect the particular row or cell. When you click a cell along with Shift key, you can select the range rows or cells from the pressed cell to the current cell.

Customizing mouse and keyboard behaviors

You can customize mouse and keyboard behaviors by overriding the selection controller. You can refer the section Customizing Selection Behaviors to override the selection controller.

Events Processed on Selection

CurrentCellActivating Event

The CurrentCellActivating event will occurs before moving the current cell to particular cell. CurrentCellActivatingEventArgs has following members which provides information for CurrentCellActivating event.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       CurrentCellActivating="sfDataGrid_CurrentCellActivating"
                       ItemsSource="{Binding Orders}">
this.sfDataGrid.CurrentCellActivating += sfDataGrid_CurrentCellActivating;

void sfDataGrid_CurrentCellActivating(object sender, CurrentCellActivatingEventArgs e)
{
}

You can cancel the current cell moving process within this event by setting GridCurrentCellActivatingEventArgs.Cancel as true.

void sfDataGrid_CurrentCellActivating(object sender, CurrentCellActivatingEventArgs e)
{
    object record = null;
    var provider = this.sfDataGrid.View.GetPropertyAccessProvider();
    var rowIndex = this.sfDataGrid.ResolveToRecordIndex(e.CurrentRowColumnIndex.RowIndex);
    if (this.sfDataGrid.View.GroupDescriptions.Count > 0)
    {
        var displayElement = this.sfDataGrid.View.TopLevelGroup.DisplayElements[rowIndex];

        if (displayElement == null)
            return;
        if (displayElement is RecordEntry)
            record = ((RecordEntry)displayElement).Data;
    }
    else
    {
        record = this.sfDataGrid.View.Records[rowIndex].Data;
        if (record == null)
            return;
    }

    var column = this.sfDataGrid.Columns[this.sfDataGrid.ResolveToGridVisibleColumnIndex(e.CurrentRowColumnIndex.ColumnIndex)];
    var cellValue = provider.GetValue(record, column.MappingName);
    if (cellValue.ToString() == "1001")
        e.Cancel = true;
}

CurrentCellActivated Event

The CurrentCellActivated event will occur once the current cell is moved to corresponding cell. CurrentCellActivatedEventArgs has following members which provides information for CurrentCellActivated event.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       CurrentCellActivated="sfDataGrid_CurrentCellActivated"
                       ItemsSource="{Binding Orders}">
this.sfDataGrid.CurrentCellActivated += sfDataGrid_CurrentCellActivated;

void sfDataGrid_CurrentCellActivated(object sender, CurrentCellActivatedEventArgs e)
{
}

SelectionChanging Event

SelectionChanging event occurs before processing the selection to particular row or cell. This event will be triggered only to the keyboard and mouse interactions. GridSelectionChangingEventArgs has the following members which provides the information for SelectionChanging event.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       SelectionChanging="sfDataGrid_SelectionChanging"
                       ItemsSource="{Binding Orders}">
this.sfDataGrid.SelectionChanging += sfDataGrid_SelectionChanging;

void sfDataGrid_SelectionChanging(object sender, GridSelectionChangingEventArgs e)
{
}

You can cancel the selection process within this event by setting GridSelectionChangingEventArgs.Cancel property as true.

private void Datagrid_SelectionChanging(object sender, GridSelectionChangingEventArgs e)
{
    var unBoundRow = e.AddedItems.Where(rowInfo => (rowInfo as GridRowInfo).IsUnBoundRow).ToList();
  
    if (unBoundRow.Count() > 0)
        e.Cancel = true;
}

SelectionChanged Event

The SelectionChanged event will occurs once the selection process has been completed for particular row or cell in SfDataGrid. GridSelectionChangedEventArgs has following members which provides information for SelectionChanged event.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       SelectionChanged="sfDataGrid_SelectionChanged"
                       ItemsSource="{Binding Orders}">
this.sfDataGrid.SelectionChanged += sfDataGrid_SelectionChanged;

void sfDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
}

Appearance

Changing Selection Background and Foreground

You can change the selection background and foreground for all rows by using the SelectionBackground and SelectionForeground properties.

<dataGridSfDataGrid x:Name="sfDataGrid"
                       AllowGrouping="True"
                       ShowGroupDropArea="True"
                       SelectionBackground="#FFDFF3F4"
                       SelectionForeground="DarkBlue"
                       SelectionMode="Extended"
                       ItemsSource="{Binding Orders}">

Customizing Selection in WinUI DataGrid

Changing Current Cell Border Style

You can change the current cell border thickness and border color using CurrentCellBorderThickness and CurrentCellBorderBrush property.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       CurrentCellBorderBrush="Red"
                       CurrentCellBorderThickness="1.6"
                       ItemsSource="{Binding Orders}">

Customizing Cell Selection Border in WinUI DataGrid

Customizing Row Selection Border

You can customize the row selection by editing the control template of corresponding row controls.

<ResourceDictionary>
	<ResourceDictionary.MergedDictionaries>
		<ResourceDictionary Source="ms-appx:///Syncfusion.Core.WinUI/Themes/Common.xaml" />
		<ResourceDictionary Source="ms-appx:///Syncfusion.Grid.WinUI/Themes/themeresources.xaml" />
		<!-- Other merged dictionaries here -->
	</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

<Style TargetType="dataGrid:DataGridRowControl">
	<Setter Property="Background" Value="{ThemeResource SyncfusionDataGridRowControlBackground}" />
	<Setter Property="BorderBrush" Value="{ThemeResource SyncfusionDataGridLineStroke}" />
	<Setter Property="Foreground" Value="{ThemeResource SyncfusionDataGridRowControlForeground}"/>
	<Setter Property="RowHoverForeground" Value="{ThemeResource SyncfusionDataGridRowForegroundPointerOver}"/>
	<Setter Property="BorderThickness" Value="0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="dataGrid:DataGridRowControl">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="BorderStates">
                                <VisualState x:Name="NormalRow" />
                                    <VisualState x:Name="FrozenRow">
                                        <Storyboard BeginTime="0">
                                            <ObjectAnimationUsingKeyFrames BeginTime="0"
												   Duration="1"
												   Storyboard.TargetName="PART_RowBorder"
												   Storyboard.TargetProperty="BorderThickness">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="0, 0, 0, 1" />
                                             </ObjectAnimationUsingKeyFrames>
                                        /Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="FooterRow">
                                        <Storyboard BeginTime="0">
                                            <ObjectAnimationUsingKeyFrames BeginTime="0"
												   Duration="1"
												   Storyboard.TargetName="PART_RowBorder"
												   Storyboard.TargetProperty="BorderThickness">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="0, 1, 0, 0" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames BeginTime="0"
												   Duration="1"
												   Storyboard.TargetName="PART_RowBorder"
												   Storyboard.TargetProperty="Margin">
											    <DiscreteObjectKeyFrame KeyTime="0" Value="0, -1, 0, 0" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="PART_RowBorder"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}" />
							<Rectangle x:Name="PART_CurrentFocusRow"
							   Margin="{TemplateBinding CurrentFocusBorderMargin}"
							   Stroke="{ThemeResource SyncfusionDataGridRowBorderFocused}"
							   StrokeDashArray="3,3"
							   StrokeThickness="1"
							   Visibility="{TemplateBinding CurrentFocusRowVisibility}" />
                            <Rectangle x:Name="PART_RowBackgroundClipRect" Fill="{TemplateBinding Background}" />
                                <!--Adding new border to show border for whole selected row-->
                            <Border x:Name="PART_RowSelectionBorder"
								BorderBrush="Red"
								BorderThickness="1.5"
								Opacity="0.75"                            
								Background="{TemplateBinding SelectionBackground}"
								Visibility="{TemplateBinding SelectionBorderVisibility}" />
                            <Border x:Name="PART_RowHighlightBorder"                                
								Background="{ThemeResource SyncfusionDataGridRowBackgroundPointerOver}"
								BorderBrush="{ThemeResource SyncfusionDataGridRowBackgroundPointerOver}"
								BorderThickness="{ThemeResource SyncfusionDataGridRowBorderThickessPointerOver}"
								Visibility="{TemplateBinding HighlightSelectionBorderVisibility}" />
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                                <ContentPresenter />
                            </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
 </Style>

Customizing Row Selection Border in WinUI DataGrid

Customizing Cell Selection

You can customize the cell selection by editing the control template of the corresponding cell control.

<ResourceDictionary>
	<ResourceDictionary.MergedDictionaries>
		<ResourceDictionary Source="ms-appx:///Syncfusion.Core.WinUI/Themes/Common.xaml" />
		<ResourceDictionary Source="ms-appx:///Syncfusion.Grid.WinUI/Themes/themeresources.xaml" />
		<!-- Other merged dictionaries here -->
	</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

<ControlTemplate x:Key="DataGridCellValidationToolTipTemplate">
    <Grid x:Name="PART_ToolTipPresenter"
          Margin="5,0"
          Opacity="0"
          RenderTransformOrigin="0,0">
		<Grid.RenderTransform>
			<TranslateTransform x:Name="Transform" X="-25" />
		</Grid.RenderTransform>
		<VisualStateManager.VisualStateGroups>
			<VisualStateGroup x:Name="OpenStates">
				<VisualStateGroup.Transitions>
					<VisualTransition GeneratedDuration="0" />
					<VisualTransition GeneratedDuration="0:0:0.2" To="Opened">
						<Storyboard>
							<DoubleAnimation Duration="0:0:0.2"
									 Storyboard.TargetName="Transform"
									 Storyboard.TargetProperty="X"
									 To="0">
								<DoubleAnimation.EasingFunction>
									<BackEase Amplitude=".3" EasingMode="EaseOut" />
								</DoubleAnimation.EasingFunction>
							</DoubleAnimation>
							<DoubleAnimation Duration="0:0:0.2"
									 Storyboard.TargetName="PART_ToolTipPresenter"
									 Storyboard.TargetProperty="Opacity"
									 To="1" />
						</Storyboard>
					</VisualTransition>
				</VisualStateGroup.Transitions>
				<VisualState x:Name="Closed">
					<Storyboard>
						<DoubleAnimation Duration="0"
								 Storyboard.TargetName="PART_ToolTipPresenter"
								 Storyboard.TargetProperty="Opacity"
								 To="0" />
					</Storyboard>
				</VisualState>
				<VisualState x:Name="Opened">
					<Storyboard>
						<DoubleAnimation Duration="0"
								 Storyboard.TargetName="Transform"
								 Storyboard.TargetProperty="X"
								 To="0" />
						<DoubleAnimation Duration="0"
								 Storyboard.TargetName="PART_ToolTipPresenter"
								 Storyboard.TargetProperty="Opacity"
								 To="1" />
					</Storyboard>
				</VisualState>
			</VisualStateGroup>
		</VisualStateManager.VisualStateGroups>

		<Border Margin="4,4,-4,-4"
			Background="Transparent"
			CornerRadius="5" />
		<Border Margin="3,3,-3,-3"
			Background="Transparent"
			CornerRadius="4" />
		<Border Margin="2,2,-2,-2"
			Background="Transparent"
			CornerRadius="3" />
		<Border Margin="1,1,-1,-1"
			Background="Transparent"
			CornerRadius="2" />

		<Border Background="{ThemeResource SystemFillColorCritical}" CornerRadius="2" />
		<Border CornerRadius="2" BorderBrush="{ThemeResource SystemFillColorCritical}">
			<TextBlock MaxWidth="250"
			   Margin="8,4,8,4"
			   FontFamily="{ThemeResource SyncfusionDataGridFontFamily}"
			   FontSize="{ThemeResource SyncfusionBodyFontSize}"
			   FontWeight="{ThemeResource SyncfusionDataGridFontWeight}"
			   Foreground="{ThemeResource SyncfusionDataGridCellValidationToolTipErrorForeground}"
			   Text="{TemplateBinding Tag}"
			   TextWrapping="Wrap"
			   HighContrastAdjustment="None"
			   UseLayoutRounding="false" />
		</Border>
    </Grid>
</ControlTemplate>


<Style TargetType="dataGrid:GridCell">
	<Setter Property="Background" Value="Transparent" />
	<Setter Property="BorderBrush" Value="{ThemeResource SyncfusionDataGridLineStroke}" />
	<Setter Property="FontFamily" Value="{ThemeResource SyncfusionDataGridFontFamily}"/>
	<Setter Property="FontSize" Value="{ThemeResource SyncfusionBodyFontSize}"/>
	<Setter Property="FontWeight" Value="{ThemeResource SyncfusionDataGridFontWeight}"/>
	<Setter Property="BorderThickness" Value="0,0,1,1" />
	<Setter Property="Padding" Value="0,0,0,0" />
	<Setter Property="VerticalContentAlignment" Value="Center" />
	<Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="dataGrid:GridCell">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="IndicationStates">
                            <VisualState x:Name="NoError">
                            </VisualState>
							<VisualState x:Name="HasError">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_InValidCellBorder" Storyboard.TargetProperty="(UIElement.Visibility)">
										<DiscreteObjectKeyFrame KeyTime="0">
											<DiscreteObjectKeyFrame.Value>
												<Visibility>Visible</Visibility>
											</DiscreteObjectKeyFrame.Value>
										</DiscreteObjectKeyFrame>
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
                         </VisualStateGroup>
						<VisualStateGroup x:Name="BorderStates">
							<VisualState x:Name="NormalCell" />
							<VisualState x:Name="FrozenColumnCell">
								<Storyboard BeginTime="0">
									<ObjectAnimationUsingKeyFrames BeginTime="0"
														   Duration="1"
														   Storyboard.TargetName="PART_FrozenCellBorder"
														   Storyboard.TargetProperty="BorderThickness">
										<DiscreteObjectKeyFrame KeyTime="0" Value="0,0,1,0" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
							<VisualState x:Name="FooterColumnCell">
								<Storyboard BeginTime="0">
									<ObjectAnimationUsingKeyFrames BeginTime="0"
														   Duration="1"
														   Storyboard.TargetName="PART_FooterCellBorder"
														   Storyboard.TargetProperty="BorderThickness">
										<DiscreteObjectKeyFrame KeyTime="0" Value="1,0,0,0" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
							<VisualState x:Name="BeforeFooterColumnCell">
								<Storyboard BeginTime="0">
									<ObjectAnimationUsingKeyFrames BeginTime="0"
														   Duration="1"
														   Storyboard.TargetName="PART_GridCellBorder"
														   Storyboard.TargetProperty="Margin">
										<DiscreteObjectKeyFrame KeyTime="0" Value="0,0,-1,0" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
							<VisualState x:Name="CurrentCell">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_CurrentCellBorder" Storyboard.TargetProperty="(UIElement.Visibility)">
										<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
							<VisualState x:Name="SelectedCell">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_SelectionCellBorder" Storyboard.TargetProperty="(UIElement.Visibility)">
										<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
							<VisualState x:Name="SelectedCurrentCell">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_SelectionCellBorder" Storyboard.TargetProperty="(UIElement.Visibility)">
										<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
									</ObjectAnimationUsingKeyFrames>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_CurrentCellBorder" Storyboard.TargetProperty="(UIElement.Visibility)">
										<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="PART_SelectionCellBorder" Background="{TemplateBinding SelectionBackground}" Visibility="Collapsed" />
                        <Border x:Name="PART_FooterCellBorder"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"/>
                        <Border x:Name="PART_FrozenCellBorder"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"/>
                        <Border x:Name="PART_GridCellBorder"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding GridCellBorderThickness}">

                                <ContentPresenter Margin="{TemplateBinding Padding}"
                                              FontFamily="{TemplateBinding FontFamily}"
                                              FontWeight="{TemplateBinding FontWeight}"
                                              FontSize="{TemplateBinding FontSize}" />

                        </Border>
                        <Border x:Name="PART_CurrentCellBorder"  
						        Background="Transparent"
                                BorderBrush="Red"
                                BorderThickness="0.5"
                                IsHitTestVisible="False"
                                Margin="0,0,1,1"
                                Visibility="{TemplateBinding SelectionBorderVisibility}" />
								<!--Adding new border to show inner border to the CurrentCellBorder-->
                        <Border x:Name="PART_CurrentCellInnerBorder" 
                                Margin="2,2,3,3"
                                Background="Transparent"
                                BorderBrush="Red"
                                BorderThickness="0.5"
                                IsHitTestVisible="False"
                                Visibility="{TemplateBinding SelectionBorderVisibility}"/>
                        <Border x:Name="PART_InValidCellBorder"
                                Width="10"
                                Height="10"
                                HorizontalAlignment="Right"
                                VerticalAlignment="Top"
                                Visibility="Collapsed">
                                    <ToolTipService.ToolTip>

                                        <ToolTip Placement="Right"
                                         Tag="{TemplateBinding ErrorMessage}"
                                         Template="{StaticResource DataGridCellValidationToolTipTemplate}" />

                                    </ToolTipService.ToolTip>
                                    <Path Data="M0.5,0.5 L12.652698,0.5 12.652698,12.068006 z"
                                  Fill="{ThemeResource SystemFillColorCritical}"
                                  Stretch="Fill" />
                        </Border>
                     </Grid>
                 </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

Custom Cell Selection in WinUI DataGrid

Binding Selection Properties

You can bind the selection properties like SelectedItem, SelectedIndex and CurrentItem to the properties in ViewModel directly.

<dataGrid:SfDataGrid x:Name="sfDataGrid"
                       SelectedItem="{Binding DataGridSelectedItem, Mode=TwoWay}"
                       CurrentItem="{Binding DataGridCurrentItem, Mode=TwoWay}"
                       SelectedIndex="{Binding DataGridSelectedIndex, Mode=TwoWay}"
                       ItemsSource="{Binding Orders}">

Customizing Selection Behaviors

The SfDataGrid process the selection operations in selection controller. Below are the built-in selection controllers,

You can customize the default row selection behaviors by overriding GridSelectionController class and set it to SfDataGrid.SelectionController.

this.sfDataGrid.SelectionController = new GridSelectionControllerExt(this.sfDataGrid);

public class GridSelectionControllerExt:GridSelectionController
{
    public GridSelectionControllerExt(SfDataGrid dataGrid):base(dataGrid)
    {     
    }
}

Selecting all rows in a group when expanding

You can select all the rows in the group which is expanding through mouse click. To achieve this, you have to set SelectionMode as Extended or Multiple and also need to override HandlePointerOperations method in selection controller.

public class GridSelectionControllerExt:GridSelectionController
{

    public GridSelectionControllerExt(SfDataGrid dataGrid)
        :base(dataGrid)
    {     
    }
    
    public override void HandlePointerOperations(GridPointerEventArgs args, Syncfusion.UI.Xaml.Grids.ScrollAxis.RowColumnIndex rowColumnIndex)
    {
        base.HandlePointerOperations(args, rowColumnIndex);

        if (args.Operation == PointerOperation.Released)
        {

            if (this.DataGrid.View.TopLevelGroup != null)
            {

                //Get the group from the DisplayElements by resolving record index of corresponding row index
                var group = this.DataGrid.View.TopLevelGroup.DisplayElements[this.DataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex)];

                if (group != null && group is Group)
                SelectGroupRows(group as Group);
            }
        }
    }
    
    private void SelectGroupRows(Group group)
    {
 
        if (group == null || !group.IsExpanded)
            return;
 
        //Check whether the group contains inner level groups.
 
        if (group.Groups == null)
 
        {
 
            //Get the corresponding start index of record by getting it from DisplayElements .
            var startIndex = this.DataGrid.View.TopLevelGroup.DisplayElements.IndexOf(group as Group);
 
            //Resolve the recordIndex to RowIndex.
            var startRowIndex = this.DataGrid.ResolveToRowIndex(startIndex);
 
            //Gets the count of rows in the group.
            var count = group.ItemsCount + this.DataGrid.GroupSummaryRows.Count;
 
            //Select the rows from corresponding start and end row index
            this.DataGrid.SelectionController.SelectRows(startRowIndex, startRowIndex + count);
        }
 
        else
        {
 
            foreach (var gr in group.Groups)
            {
 
                //Called recursively, to traverse it inner level of group.
                SelectGroupRows(gr);
                var startIndex = this.DataGrid.View.TopLevelGroup.DisplayElements.IndexOf(group as Group);
                var startRowIndex = this.DataGrid.ResolveToRowIndex(startIndex);
 
                //Get the corresponding end index of the group by getting it from DisplayElements using the inner level group.
                var endIndex = this.DataGrid.View.TopLevelGroup.DisplayElements.IndexOf(gr as Group);
                var endRowIndex = this.DataGrid.ResolveToRowIndex(endIndex);
                this.DataGrid.SelectionController.SelectRows(startRowIndex, endRowIndex);
            }
        }
    }
}

Avoid CaptionSummaryRow selection on Grouping

While grouping any column, by default the first CaptionSummaryRow will be selected when the CurrentItem is null. You can change this action by overriding the ProcessOnGroupChanged method in selection controller.

public class GridSelectionControllerExt : GridSelectionController
{
 
    public GridSelectionControllerExt(SfDataGrid dataGrid) : base(dataGrid)
    {
    }       
 
    protected override void ProcessOnGroupChanged(GridGroupingEventArgs args)
    {
        base.ProcessOnGroupChanged(args);
        var removedItems = new List<object>();
 
        //Refresh the selection only in record rows.
        this.RefreshSelectedItems(ref removedItems);
 
        //Updates the current cell and current row.
        this.UpdateCurrentRowIndex();
    }
}