Sorting in Windows Forms DataGrid (SfDataGrid)
7 Sep 202318 minutes to read
Windows Forms DataGrid (SfDataGrid) allows to sort the data against one or more columns either in ascending or descending order. When sorting is applied, the rows are rearranged based on sort criteria.
The data can be sorted by clicking on the column headers that needs to be sorted or it can be performed programmatically. Once sorting is applied, the grid will display a sort icon in the respected column headers showing the sort direction.
The sorting can be performed by touching or clicking the column header. This can be enabled by setting SfDataGrid.AllowSorting property to true
.
this.sfDataGrid1.AllowSorting = true;
Me.sfDataGrid1.AllowSorting = True
Sorting can be enabled or disabled for the particular column by setting the GridColumnBase.AllowSorting property.
this.sfDataGrid1.Columns["OrderID"].AllowSorting = true;
this.sfDataGrid1.Columns["CustomerID"].AllowSorting = false;
Me.sfDataGrid1.Columns("OrderID").AllowSorting = True
Me.sfDataGrid1.Columns("CustomerID").AllowSorting = False
NOTE
The
GridColumn.AllowSorting
takes higher priority thanSfDataGrid.AllowSorting
property.
End users can sort the column by clicking column header cell. Once the columns get sorted, the sort indicator will be displayed on the right side of the column header.
Adding Sort Columns
The sorting can be applied programmatically by adding or removing the SortColumnDescription
in SfDataGrid.SortColumnDescriptions collection.
SortColumnDescription sortColumnDescription = new SortColumnDescription();
sortColumnDescription.ColumnName = "CustomerID";
sortColumnDescription.SortDirection = ListSortDirection.Ascending;
this.sfDataGrid1.SortColumnDescriptions.Add(sortColumnDescription);
Dim sortColumnDescription As New SortColumnDescription()
sortColumnDescription.ColumnName = "CustomerID"
sortColumnDescription.SortDirection = ListSortDirection.Ascending
Me.sfDataGrid1.SortColumnDescriptions.Add(sortColumnDescription)
Removing Sort Columns
The sorted column data can be unsorted by removing the corresponding SortColumnDescription
from the SfDataGrid.SortColumnDescriptions
collection.
var sortColumnDescription = this.sfDataGrid1.SortColumnDescriptions.FirstOrDefault(col => col.ColumnName == "OrderID");
if (sortColumnDescription != null)
{
this.sfDataGrid1.SortColumnDescriptions.Remove(sortColumnDescription);
}
Dim sortColumnDescription = Me.sfDataGrid1.SortColumnDescriptions.FirstOrDefault(Function(col) col.ColumnName = "OrderID")
If sortColumnDescription IsNot Nothing Then
Me.sfDataGrid1.SortColumnDescriptions.Remove(sortColumnDescription)
End If
Clear Sorting
The sorting can be cleared by clearing the SfDataGrid.SortColumnDescriptions
.
this.sfDataGrid1.SortColumnDescriptions.Clear();
Me.sfDataGrid1.SortColumnDescriptions.Clear()
Disable Sorting
The sorting functionality of the SfDataGrid can be disabled by setting the AllowSorting
property to false.
this.sfDataGrid1.AllowSorting = false;
Me.sfDataGrid1.AllowSorting = False
Sorting Column in Double Click
By default, column gets sorted when column header clicked. This behavior can be changed to sort the column on double click by setting the SfDataGrid.SortClickAction property to DoubleClick
.
this.sfDataGrid1.SortClickAction = SortClickAction.DoubleClick;
Me.sfDataGrid1.SortClickAction = SortClickAction.DoubleClick
Sorting Order
By default, the data is sorted in ascending or descending order when clicking column header. The data can be rearranged to its initial order from descending on clicking the column header by setting the SfDataGrid.AllowTriStateSorting property to true
.
Following are the sequence of sorting orders when clicking column header,
- Sorts the data in ascending order
- Sorts the data in descending order
- Clears the sorting and records displayed in its initial order
Retrieve the records as displayed in the view
After sorting, the records in the view can be retrieved in the same order as displayed in the view by using the SfDataGrid.View.Records collection.
foreach (var record in sfDataGrid.View.Records)
{
// Do your customizations here.
}
For Each record In sfDataGrid.View.Records
' Do your customizations here.
Next record
Multi Column Sorting
SfDataGrid control allows to sort more than one column, where sorting is applied one column against other columns. To apply sorting on multiple columns, user have to click the column header by pressing the Ctrl
key.
In the below screen shot, the OrderID column sorted. Then the ProductName column is sorted against the OrderID data by clicking column header by pressing Ctrl
key. The sorting state of OrderID column is preserved and ProductName column sorted against OrderID column.
Display Sort Order
It is also possible to display sorted order of columns in header by setting SfDataGrid.ShowSortNumbers property to true
.
this.sfDataGrid1.ShowSortNumbers = true;
Me.sfDataGrid1.ShowSortNumbers = True
Custom Sort Icon
The default sort icon can be changed by using the SortIcon property.
this.sfDataGrid1.Columns[0].HeaderStyle.SortIcon = global::GettingStarted.Properties.Resources.SortIcon;
Me.sfDataGrid1.Columns(0).HeaderStyle.SortIcon = Global.GettingStarted.Properties.Resources.SortIcon
Custom Sorting
SfDataGrid allows to sort the columns based on the custom logic. The custom sorting can be applied by adding the SortComparer
instance to SfDataGrid.SortComparers.
You can implement ISortDirection interface in comparer to get the sort direction. So you can apply different custom logics for ascending and descending.
Follow the below steps to add custom comparer to sort using custom logic,
Defining Custom Comparer
In the below code snippet, ProductName column is compared based on its string length, instead of default string comparison.
public class CustomComparer:IComparer<object>,ISortDirection
{
public int Compare(object x, object y)
{
int nameX;
int nameY;
//While data object passed to comparer
if (x.GetType() == typeof(OrderInfo))
{
nameX = ((OrderInfo)x).ProductName.Length;
nameY = ((OrderInfo)y).ProductName.Length;
}
//While sorting groups
else if (x.GetType() == typeof(Group))
{
//Calculating the group key length
nameX = ((Group)x).Key.ToString().Length;
nameY = ((Group)y).Key.ToString().Length;
}
else
{
nameX = x.ToString().Length;
nameY = y.ToString().Length;
}
//returns the comparison result based in SortDirection.
if (nameX.CompareTo(nameY) > 0)
return SortDirection == ListSortDirection.Ascending ? 1 : -1;
else if (nameX.CompareTo(nameY) == -1)
return SortDirection == ListSortDirection.Ascending ? -1 : 1;
else
return 0;
}
private ListSortDirection _SortDirection;
/// <summary>
/// Gets or sets the property that denotes the sort direction.
/// </summary>
/// <remarks>
/// SortDirection gets updated only when sorting the groups. For other cases, SortDirection is always ascending.
/// </remarks>
public ListSortDirection SortDirection
{
get { return _SortDirection; }
set { _SortDirection = value; }
}
}
Public Class CustomComparer
Implements IComparer(Of Object), ISortDirection
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer
Dim nameX As Integer
Dim nameY As Integer
'While data object passed to comparer
If x.GetType() Is GetType(OrderInfo) Then
nameX = (CType(x, OrderInfo)).ProductName.Length
nameY = (CType(y, OrderInfo)).ProductName.Length
'While sorting groups
ElseIf x.GetType() Is GetType(Group) Then
'Calculating the group key length
nameX = (CType(x, Group)).Key.ToString().Length
nameY = (CType(y, Group)).Key.ToString().Length
Else
nameX = x.ToString().Length
nameY = y.ToString().Length
End If
'returns the comparison result based in SortDirection.
If nameX.CompareTo(nameY) > 0 Then
Return If(SortDirection = ListSortDirection.Ascending, 1, -1)
ElseIf nameX.CompareTo(nameY) = -1 Then
Return If(SortDirection = ListSortDirection.Ascending, -1, 1)
Else
Return 0
End If
End Function
Private _SortDirection As ListSortDirection
''' <summary>
''' Gets or sets the property that denotes the sort direction.
''' </summary>
''' <remarks>
''' SortDirection gets updated only when sorting the groups. For other cases, SortDirection is always ascending.
''' </remarks>
Public Property SortDirection() As ListSortDirection
Get
Return _SortDirection
End Get
Set(ByVal value As ListSortDirection)
_SortDirection = value
End Set
End Property
End Class
Adding Custom Comparer
Custom comparer can be added to SfDataGrid.SortComparers
property. SortComparers
maintains custom comparers and the custom comparer gets called when corresponding column gets sorted by clicking column header or programmatically.
this.sfDataGrid1.SortComparers.Add(new Syncfusion.Data.SortComparer() { Comparer = new CustomComparer(), PropertyName = "ProductName" });
Me.sfDataGrid1.SortComparers.Add(New Syncfusion.Data.SortComparer() With {.Comparer = New CustomComparer(), .PropertyName = "ProductName"})
While performing the Sorting, the ProductName column sorts the data using custom comparer available in SfDataGrid.SortComparers
.
Canceling Sorting for a Specific Column
The sorting for a particular column can be canceled by using the SortColumnsChanging event through Cancel
property.
this.sfDataGrid1.SortColumnsChanging += SfDataGrid1_SortColumnsChanging;
private void SfDataGrid1_SortColumnsChanging(object sender, SortColumnsChangingEventArgs e)
{
if (e.AddedItems[0].ColumnName == "OrderID")
{
e.Cancel = true;
}
}
AddHandler sfDataGrid1.SortColumnsChanging, AddressOf SfDataGrid1_SortColumnsChanging
Private Sub SfDataGrid1_SortColumnsChanging(ByVal sender As Object, ByVal e As SortColumnsChangingEventArgs)
If e.AddedItems(0).ColumnName = "OrderID" Then
e.Cancel = True
End If
End Sub
Customization using Events
Canceling Scrolling after Sorting
The scrolling after the sorting to bring SelectedItem in view can be canceled by using the SortColumnsChanging
event through CancelScroll property.
this.sfDataGrid1.SortColumnsChanging += SfDataGrid1_SortColumnsChanging;
private void SfDataGrid1_SortColumnsChanging(object sender, SortColumnsChangingEventArgs e)
{
e.CancelScroll = true;
}
AddHandler sfDataGrid1.SortColumnsChanging, AddressOf SfDataGrid1_SortColumnsChanging
Private Sub SfDataGrid1_SortColumnsChanging(ByVal sender As Object, ByVal e As SortColumnsChangingEventArgs)
e.CancelScroll = True
End Sub
Sorting the Underlying Collection
SfDataGrid
sorts the records in UI and maintains in its internal CollectionView and it will not change the order of data in underlying collection.
You can get sorted data from SfDataGrid.View.Records
when groups is not in place and SfDataGrid.View.TopLevelGroup.DisplayElements when grouping in place.
If you want to sort the underlying collection when sorting takes place, this can be achieved by handling SfDataGrid.SortColumnsChanged event.
ViewModel viewModel = new ViewModel();
this.dataGrid.SortColumnsChanged += dataGrid_SortColumnsChanged;
private void dataGrid_SortColumnsChanged(object sender, SortColumnsChangedEventArgs e)
{
IEnumerable<OrderInfo> OrderedSource = viewModel.Orders;
foreach (var sortColumn in this.dataGrid.View.SortDescriptions)
{
var columnName = sortColumn.PropertyName;
if (sortColumn.Direction == ListSortDirection.Ascending)
OrderedSource = OrderedSource.OrderBy(source => GetOrderSource(source, columnName));
else
OrderedSource = OrderedSource.OrderByDescending(source => GetOrderSource(source, columnName));
}
}
private object GetOrderSource(OrderInfo source, string name)
{
var propInfo = source.GetType().GetRuntimeProperty(name);
if (propInfo != null)
// get the current sort column value
return propInfo.GetValue(source);
return null;
}
Dim viewModel As ViewModel = New ViewModel()
AddHandler Me.dataGrid.SortColumnsChanged, AddressOf dataGrid_SortColumnsChanged
Private Sub dataGrid_SortColumnsChanged(ByVal sender As Object, ByVal e As SortColumnsChangedEventArgs)
Dim OrderedSource As IEnumerable(Of OrderInfo) = viewModel.Orders
For Each sortColumn In Me.dataGrid.View.SortDescriptions
Dim columnName = sortColumn.PropertyName
If sortColumn.Direction = ListSortDirection.Ascending Then
OrderedSource = OrderedSource.OrderBy(Function(source) GetOrderSource(source, columnName))
Else
OrderedSource = OrderedSource.OrderByDescending(Function(source) GetOrderSource(source, columnName))
End If
Next sortColumn
End Sub
Private Function GetOrderSource(ByVal source As OrderInfo, ByVal name As String) As Object
Dim propInfo = source.GetType().GetRuntimeProperty(name)
If propInfo IsNot Nothing Then
' get the current sort column value
Return propInfo.GetValue(source)
End If
Return Nothing
End Function