Editing in WPF DataGrid (SfDataGrid)
22 Sep 202324 minutes to read
WPF DataGrid provides support for editing and it can be enabled or disabled by setting SfDataGrid.AllowEditing property.
<syncfusion:SfDataGrid x:Name="dataGrid"
AllowEditing="True"
AutoGenerateColumns="True"
ItemsSource="{Binding Orders}" />
dataGrid.AllowEditing = true;
You can enable or disable editing for particular column by setting GridColumn.AllowEditing property.
<syncfusion:GridTextColumn AllowEditing="True" MappingName="OrderID" />
dataGrid.Columns["OrderID"].AllowEditing = true;
NOTE
GridColumn.AllowEditing takes higher priority than SfDataGrid.AllowEditing.
NOTE
It is mandatory to set the NavigationMode to Cell to enable CurrentCell navigation and editing.
Edit mode
You can enter into edit mode by pressing F2 key or clicking (touch also supported) the cell. You can allow users to edit the cell in single click (OnTap) or double click (OnDoubleTab) by setting by EditTrigger property.
<syncfusion:SfDataGrid x:Name="dataGrid"
AllowEditing="True"
EditTrigger="OnTap"
ItemsSource="{Binding Orders}" />
dataGrid.EditTrigger = EditTrigger.OnTap;
Edit cursor placement
When the cell enters into edit mode, cursor is placed based on EditorSelectionBehavior property.
-
SelectAll – selects the text of edit element loaded inside cell.
-
MoveLast – places the cursor at the last of edit element loaded inside cell.
<syncfusion:SfDataGrid x:Name="dataGrid"
AllowEditing="True"
EditorSelectionBehavior="SelectAll"
ItemsSource="{Binding Orders}" />
dataGrid.EditorSelectionBehavior = EditorSelectionBehavior.SelectAll;
Retain editing on lost focus
The editing of current cell will be ended by default while the focus is moving from DataGrid to another control. You can set the LostFocusBehavior property to LostFocusBehavior.Default
if you want to retain the editing of the current cell even when focus is moved to another control.
<syncfusion:SfDataGrid x:Name="dataGrid"
AllowEditing="True"
LostFocusBehavior="Default"
ItemsSource="{Binding Orders}" />
dataGrid.LostFocusBehavior = LostFocusBehavior.Default;
Working with IEditableObject interface
WPF DataGrid (SfDataGrid) supports to commit and roll back the changes in row level when underlying data object implements IEditableObject interface.
The editing changes in a row will be committed only when user move to next row or pressing enter key in EndEdit. Also when user press Esc key, then the changes made in a row will be reverted in CancelEdit.
IEditableObject
has the following methods to capture editing,
-
BeginEdit – Gets called to begin edit on underlying data object when cell in a row get into edit mode.
-
CancelEdit – Gets called when user press the Esc key to discard the changes in a row since last
BeginEdit
call. -
EndEdit – Gets called when user move to the next row or press Enter key to commit changes in underlying data object since last
BeginEdit
call.
In the below code snippet explains the simple implementation of IEditableObject
.
public class Employee : NotificationObject, IEditableObject
{
private string _Name;
private int _ContactID;
private string _Title;
private DateTime _BirthDate;
private string _Gender;
private double _SickLeaveHours;
private double _Salary;
protected Dictionary<string, object> BackUp()
{
var dict = new Dictionary<string, object>();
var itemProperties = this.GetType().GetTypeInfo().DeclaredProperties;
foreach (var pDescriptor in itemProperties)
{
if (pDescriptor.CanWrite)
dict.Add(pDescriptor.Name, pDescriptor.GetValue(this));
}
return dict;
}
public string Name
{
get { return this._Name; }
set
{
this._Name = value;
this.RaisePropertyChanged("Name");
}
}
public string Title
{
get { return this._Title; }
set
{
this._Title = value;
this.RaisePropertyChanged("Title");
}
}
public int ContactID
{
get { return this._ContactID; }
set
{
this._ContactID = value;
this.RaisePropertyChanged("ContactID");
}
}
public DateTime BirthDate
{
get { return this._BirthDate; }
set
{
this._BirthDate = value;
this.RaisePropertyChanged("BirthDate");
}
}
public string Gender
{
get { return this._Gender; }
set
{
this._Gender = value;
this.RaisePropertyChanged("Gender");
}
}
public double SickLeaveHours
{
get { return this._SickLeaveHours; }
set
{
this._SickLeaveHours = value;
this.RaisePropertyChanged("SickLeaveHours");
}
}
public double Salary
{
get { return this._Salary; }
set
{
this._Salary = value;
this.RaisePropertyChanged("Salary");
}
}
private int _EmployeeID;
public int EmployeeID
{
get { return this._EmployeeID; }
set
{
this._EmployeeID = value;
this.RaisePropertyChanged("EmployeeID");
}
}
private Dictionary<string, object> storedValues;
public void BeginEdit()
{
this.storedValues = this.BackUp();
}
public void CancelEdit()
{
if (this.storedValues == null)
return;
foreach (var item in this.storedValues)
{
var itemProperties = this.GetType().GetTypeInfo().DeclaredProperties;
var pDesc = itemProperties.FirstOrDefault(p => p.Name == item.Key);
if (pDesc != null)
pDesc.SetValue(this, item.Value);
}
}
public void EndEdit()
{
if (this.storedValues != null)
{
this.storedValues.Clear();
this.storedValues = null;
}
Debug.WriteLine("End Edit Called");
}
}
public class NotificationObject : INotifyPropertyChanged
{
public void RaisePropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Edit events
SfDataGrid triggers the following events during editing.
CurrentCellBeginEdit Event
CurrentCellBeginEdit event occurs when the CurrentCell enter into edit mode. CurrentCellBeginEditEventArgs has following members which provides information for CurrentCellBeginEdit
event.
-
Cancel : When set to
true
, the event is canceled and theCurrentCell
does not enter into the edit mode. - RowColumnIndex : Gets the current row column index of the DataGrid.
- Column : Gets the Grid Column of the SfDataGrid.
this.dataGrid.CurrentCellBeginEdit += dataGrid_CurrentCellBeginEdit;
void dataGrid_CurrentCellBeginEdit(object sender, Syncfusion.UI.Xaml.Grid.CurrentCellBeginEditEventArgs args)
{
}
CurrentCellEndEdit Event
CurrentCellEndEdit event occurs when the CurrentCell exits the edit mode. CurrentCellEndEditEventArgs has following members which provides information for CurrentCellEndEdit
event.
- RowColumnIndex : Gets the value for the current row column index.
this.dataGrid.CurrentCellEndEdit += dataGrid_CurrentCellEndEdit;
void dataGrid_CurrentCellEndEdit(object sender, Syncfusion.UI.Xaml.Grid.CurrentCellEndEditEventArgs args)
{
}
CurrentCellValueChanged Event
CurrentCellValueChanged event occurs whenever a value changes in GridColumn’s that supports editing. CurrentCellValueChangedEventArgs has following members which provides information for CurrentCellValueChanged
event.
- Column : Gets the Grid Column of the SfDataGrid.
- RowColumnIndex : Gets the value of the current RowColumnIndex.
this.dataGrid.CurrentCellValueChanged += dataGrid_CurrentCellValueChanged;
void dataGrid_CurrentCellValueChanged(object sender, Syncfusion.UI.Xaml.Grid.CurrentCellValueChangedEventArgs args)
{
}
NOTE
GridComboBoxColumn
andGridMultiColumnDropList
, you have to use theCurrentCellDropDownSelectionChanged
event.
Combobox column selectionchanged event
CurrentCellDropDownSelectionChanged event occurs whenever the SelectedItem
of GridMultiColumnDropDownList
and GridComboBoxColumn
column changed.
CurrentCellDropDownSelectionChangedEventArgs has following members which provides information for CurrentCellDropDownSelectionChanged
event.
- RowColumnIndex – Gets the RowColumnIndex of the corresponding item that were selected from the drop-down control.
- SelectedIndex – Gets the index of the corresponding item that were selected from the drop-down control.
- SelectedItem – Gets the data item that were selected from the drop-down control.
this.dataGrid.CurrentCellDropDownSelectionChanged += dataGrid_CurrentCellDropDownSelectionChanged;
void dataGrid_CurrentCellDropDownSelectionChanged(object sender, CurrentCellDropDownSelectionChangedEventArgs args)
{
}
Programmatically edit the cell
BeginEdit
WPF DataGrid (SfDataGrid) allows you to edit the cell programmatically by calling the BeginEdit method. Initially the CurrentCell need to set before calling the BeginEdit
method when the CurrentCell value is null.
//Add this namespace to access the RowColumnIndex structure type in SfDataGrid
using Syncfusion.UI.Xaml.ScrollAxis;
this.dataGrid.Loaded += dataGrid_Loaded;
void dataGrid_Loaded(object sender, RoutedEventArgs e)
{
RowColumnIndex rowColumnIndex = new RowColumnIndex(3, 2);
this.dataGrid.MoveCurrentCell(rowColumnIndex);
this.dataGrid.SelectionController.CurrentCellManager.BeginEdit();
}
EndEdit
You can call the EndEdit method to programmatically end edit.
//Add this namespace to access the RowColumnIndex structure type in SfDataGrid
using Syncfusion.UI.Xaml.ScrollAxis;
this.dataGrid.Loaded += dataGrid_Loaded;
void dataGrid_Loaded(object sender, RoutedEventArgs e)
{
RowColumnIndex rowColumnIndex = new RowColumnIndex(3, 2);
this.dataGrid.MoveCurrentCell(rowColumnIndex);
this.dataGrid.SelectionController.CurrentCellManager.EndEdit();
}
CancelEdit
You can use the CurrentCellBeginEdit event to cancel the editing operation for the corresponding cell.
//Add this namespace to access the RowColumnIndex structure type in SfDataGrid
using Syncfusion.UI.Xaml.ScrollAxis;
this.dataGrid.CurrentCellBeginEdit += dataGrid_CurrentCellBeginEdit;
void dataGrid_CurrentCellBeginEdit(object sender, Syncfusion.UI.Xaml.Grid.CurrentCellBeginEditEventArgs args)
{
var recordIndex = this.dataGrid.ResolveToRecordIndex(args.RowColumnIndex.RowIndex);
var columnIndex = this.dataGrid.ResolveToGridVisibleColumnIndex(args.RowColumnIndex.ColumnIndex);
var mappingName = this.dataGrid.Columns[columnIndex].MappingName;
var record = this.dataGrid.View.Records.GetItemAt(recordIndex);
var cellValue = this.dataGrid.View.GetPropertyAccessProvider().GetValue(record, mappingName);
if (args.RowColumnIndex == new RowColumnIndex(3, 2))
args.Cancel = true;
}
Cell click events
WPF DataGrid provides CellTapped
and CellDoubleTapped
events to handle cell click actions.
Cell tapped event
WPF DataGrid CellTapped
event occurs when the user clicks or touches a cell in DataGrid with GridCellTappedEventArgs. CellTapped
event does not occur for the non-selectable cells. The GridCellTappedEventArgs
has following members which provides information for CellTapped
event.
- Column - Gets the GridColumn of the tapped cell.
- Record - Gets the data context of the tapped cell.
- RowColumnIndex - Gets the RowColumnIndex of the tapped cell.
- ChangedButton - Get the MouseButton associated with the event.
- OriginalSender - Gets the original reporting source that raised the event.
<Syncfusion:SfDataGrid x:Name="dataGrid"
CellTapped="datagrid_CellTapped"
ItemsSource="{Binding OrderInfoCollection }">
</Syncfusion:SfDataGrid>
this.dataGrid.CellTapped += Datagrid_CellTapped;
private void Datagrid_CellTapped(object sender, GridCellTappedEventArgs e)
{
//You can do your own logic here.
}
Cell double tapped event
CellDoubleTapped
event occurs when the user double clicks or double taps a cell in DataGrid with GridCellDoubleTappedEventArgs. CellDoubleTapped
event does not occur for non-selectable cells. GridCellDoubleTappedEventArgs
has following members which provides information for CellDoubleTapped
event.
- Column - Gets the GridColumn of the double tapped cell.
- Record - Gets the data context of the double tapped cell.
- RowColumnIndex - Gets the RowColumnIndex of the double tapped cell.
- ChangedButton - Gets the MouseButton associated with the event.
- OriginalSender - Gets the original reporting source that raised the event.
<Syncfusion:SfDataGrid x:Name="dataGrid"
CellDoubleTapped="datagrid_CellDoubleTapped"
ItemsSource="{Binding OrderInfoCollection }">
</Syncfusion:SfDataGrid>
this.dataGrid.CellDoubleTapped += Datagrid_CellDoubleTapped;
private void Datagrid_CellDoubleTapped(object sender, GridCellDoubleTappedEventArgs e)
{
//you can do your own logic here.
}
Mouse and Keyboard operations for UIElement inside Template
You can directly load edit element using GridTemplateColumn.CellTemplate
property. In this case, you can provide focus and control (keyboard and mouse) to the UIElement inside CellTemplate in the below ways,
Providing focus to the control inside the Template
You can focus to the particular UIElement loaded inside template when cell gets activated by setting FocusedManager.FocusedElement attached property.
<syncfusion:GridTemplateColumn HeaderText="Customer ID"
MappingName="CustomerID" >
<syncfusion:GridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock syncfusion:FocusManagerHelper.FocusedElement="True"
FontStyle="Italic"
FontWeight="SemiBold"
Padding="2,0"
Text="{Binding CustomerID}" />
</DataTemplate>
</syncfusion:GridTemplateColumn.CellTemplate>
</syncfusion:GridTemplateColumn>
Providing keyboard control to UIElement inside CellTemplate
You can allow UIElement
loaded inside CellTemplate
to handle keyboard interaction by setting FocusManagerHelper.WantsKeyInput attached property to GridColumn
.
<syncfusion:GridTemplateColumn MappingName="ProductId"
syncfusion:FocusManagerHelper.WantsKeyInput= "True">
<syncfusion:GridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBox x:Name="text" Text="{Binding ProductId}"/>
</Grid>
</DataTemplate>
</syncfusion:GridTemplateColumn.CellTemplate>
</syncfusion:GridTemplateColumn>
NOTE
Enter and Tab keys are always handled by
SfDataGrid
only.
Providing mouse control to UIElement inside Template
You can allow UIElement
loaded inside template to handle mouse interaction in required cases by setting VisualContainer.WantsMouseInput attached property to GridColumn
.
<syncfusion:SfDataGrid x:Name="dataGrid"
AutoGenerateColumns="False"
ItemsSource="{Binding Orders}">
<syncfusion:SfDataGrid.Columns>
<syncfusion:GridTemplateColumn MappingName="ProductName">
<syncfusion:GridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ComboItems, Source={StaticResource viewModel}}"
syncfusion:VisualContainer.WantsMouseInput="True" />
</DataTemplate>
</syncfusion:GridTemplateColumn.CellTemplate>
</syncfusion:GridTemplateColumn>
</syncfusion:SfDataGrid.Columns>
</syncfusion:SfDataGrid>
How to
How to track edited cells in WPF DataGrid?
You can change the foreground color of edited cells through the CellStyleSelector
to track edited cells.
Please follow the below steps to highlight the edited cells.
- Add new property
EditedColumns
in data object to maintain edited columnMappingName
. -
Add the
MappingName
of the column toEditedColumns
, inCurrentCellValueChanged
event to keep track of edited columns in data object.this.dataGrid.CurrentCellValueChanged+=dataGrid_CurrentCellValueChanged; private void dataGrid_CurrentCellValueChanged(object sender, CurrentCellValueChangedEventArgs args) { if (!(args.Record as OrderInfo).EditedColumns.Contains(args.Column.MappingName)) (args.Record as OrderInfo).EditedColumns.Add(args.Column.MappingName); //updates the current row index this.dataGrid.UpdateDataRow(args.RowColumnIndex.RowIndex); }
- Create a style of TargetType
GridCell
and change the Foreground usingCellStyleSelector
based onEditedColumns
property in data object.
<Application.Resources>
<Style x:Key="cellStyle" TargetType="syncfusion:GridCell">
<Setter Property="Foreground" Value="DarkOrange" />
</Style>
</Application.Resources>
<Window.Resources>
<local:CellStyleSelector x:Key="cellStyleSelector" />
</Window.Resources>
<syncfusion:SfDataGrid x:Name="dataGrid"
CellStyleSelector="{StaticResource cellStyleSelector}"
AllowEditing="True"
ItemsSource="{Binding Path=OrdersDetails}"
ShowRowHeader="True">
</syncfusion:SfDataGrid>
public class CellStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
var gridCell = container as GridCell;
if (gridCell.ColumnBase == null || gridCell.ColumnBase.GridColumn == null)
base.SelectStyle(item, container);
var record = item as OrderInfo;
if (record.EditedColumns.Contains(gridCell.ColumnBase.GridColumn.MappingName))
return App.Current.Resources["cellStyle"] as Style;
return base.SelectStyle(item, container);
}
}
Allow editing when pressing minus key
SfDataGrid does not allow the cell to get into the edit mode while pressing the Minus key or any special character. You can overcome this behavior by customizing the SfDataGrid class, and overriding its OnTextInput()
method.
public class SfDataGridExt : SfDataGrid
{
public SfDataGridExt()
: base()
{
}
protected override void OnTextInput(TextCompositionEventArgs e)
{
if (!SelectionController.CurrentCellManager.HasCurrentCell)
{
base.OnTextInput(e);
return;
}
//Get the Current Row and Column index from the CurrentCellManager
var rowColumnIndex = SelectionController.CurrentCellManager.CurrentRowColumnIndex;
RowGenerator rowGenerator = this.RowGenerator;
//Get the row from the Row index
var dataRow = rowGenerator.Items.FirstOrDefault(item => item.RowIndex == rowColumnIndex.RowIndex);
//Check whether the dataRow is null or not and the type as DataRow
if (dataRow != null && dataRow is DataRow)
{
//Get the column from the VisibleColumn collection based on the column index
var dataColumn = dataRow.VisibleColumns.FirstOrDefault(column => column.ColumnIndex == rowColumnIndex.ColumnIndex);
//Convert the input text to char type
char text;
char.TryParse(e.Text, out text);
//Skip if the column is GridTemplateColumn and the column is not already in editing
//Allow Editing only pressed letters digits and Minus sign key
if (dataColumn != null && !(dataColumn.GridColumn is GridTemplateColumn) && !dataColumn.IsEditing && SelectionController.CurrentCellManager.BeginEdit() && (e.Text.Equals("-") || char.IsLetterOrDigit(text)))
dataColumn.Renderer.PreviewTextInput(e);
}
base.OnTextInput(e);
}
}
See Also
How to show different controls in same column of SfDataGrid?
How to edit GridHyperLinkColumn?
How to use the editing related events in GridCheckBoxColumn?
How to skip editing for Read-Only columns in AddNewRow?
How to change the cell value of selectedcells when end edit?
How to show the Number Keyboard when editing GridNumericColumn?
How to validate the AddNewRow value based on already existing records?
How to change the CheckBox value for all SelectedItems when any selected CheckBox value changed?
How to fire RowValidating event for GridCheckBoxColumn in SfDataGrid
How to create ReadOnly UnboundRows?
How to load null value to the GridDateTimeColumn when AllowInlineEditing is set to true?
How to customize edit mode behavior of GridCell in SfDataGrid?
How to change the Enter key behavior in SfDataGrid?
How to change the Enter key behavior to insert line break when the CurrentCell is in the edit mode?
How to edit SfDataGrid Template column by single tap?
How to set the Copy and Paste option of the Grid by using ContextMenu and SfRibbon?
How to hide the rows based on condition in SfDataGrid?
How to disable Edit mode for cells in SfDataGrid with different background for those disabled cells?
How to change the same values in all records when the ComboBox column value is changed?
How to disable the edit mode of AddNewRow in SfDataGrid when AllowEditing is set as False?
How to get the parent grid while editing the child grid?
How to handle keyboard and mouse interactions for GridTemplateColumn?