CRUD Operations in WinUI DataGrid
17 May 202224 minutes to read
DataGrid listens and responds to the CRUD operations such as add, delete and data update (property change) at runtime. Also, it supports editing, add new row, delete row by pressing Delete key.
Managing data updates
DataGrid manages the sorting, filtering, grouping and summaries during data updates based on SfDataGrid.LiveDataUpdateMode property.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AutoGenerateColumns="True"
ItemsSource="{Binding Orders}"
LiveDataUpdateMode="AllowDataShaping" />
this.sfDataGrid.LiveDataUpdateMode = LiveDataUpdateMode.AllowDataShaping;
LiveDataUpdateMode – Default
Grid operations / Data Manipulation operations |
Add |
Remove / delete |
Property change |
Sorting | Record added at last | Updated | Sort order not updated |
Grouping | Updated | Updated | Groups not refreshed based on change |
Filtering | Updated | Updated | Filter not refreshed based on change |
Summaries | Not updated | Not updated | Not updated |
LiveDataUpdateMode – AllowSummaryUpdate
Grid operations/ Data Manipulation operations |
Add |
Remove / delete |
Property change |
Sorting | Record added at last | Updated | Sort order not updated |
Grouping | Updated | Updated | Groups not refreshed based on change |
Filtering | Updated | Updated | Filter not refreshed based on change |
Summaries | Updated | Updated | Updated |
LiveDataUpdateMode – AllowDataShaping
Grid operations/ Data Manipulation operations |
Add |
Remove / delete |
Property change |
Sorting | Updated | Updated | Updated |
Grouping | Updated | Updated | Updated |
Filtering | Updated | Updated | Updated |
Summaries | Updated | Updated | Updated |
Limitations
-
AllowDataShaping
andAllowSummaryUpdate
is not supported when you are binding with dynamic data objects. - Complex and indexer properties doesn’t support
LiveDataUpdateMode
-AllowDataShaping
andAllowSummaryUpdate
.
Add new rows
DataGrid provides built-in row (called AddNewRow) that allows user to add new records to underlying collection. Built-in add new row can be enabled or disabled by setting SfDataGrid.AddNewRowPosition property. AddNewRowPosition
also denotes the position of add new row in DataGrid.
When you start editing in AddNewRow, the SfDataGrid control creates an instance for the underlying data object and adds it to underlying collection when editing completed.
NOTE
The underlying data object must be defined with default constructor.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AddNewRowPosition="Top"
AutoGenerateColumns="True"
ItemsSource="{Binding Orders}" />
this.sfDataGrid.AddNewRowPosition = AddNewRowPosition.Top;
You can get the row row index of AddNewRow using SfDataGrid.GetAddNewRowIndex method.
int addNewRowIndex = this.sfDataGrid.GetAddNewRowIndex();
You can check whether the specified row index is AddNewRow index, by using SfDataGrid.IsAddNewIndex helper method.
bool isAddNewRowIndex = this.sfDataGrid.IsAddNewIndex(1);
Changing the AddNewRow default text in DataGrid
You can change the default static string of AddNewRow in datagrid by using the SfDataGrid.AddNewRowText property. The AddNewRowText
property has higher priority than the text that is localized in resx file.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AddNewRowPosition="Top"
AddNewRowText="Click here to add new row in datagrid"
ItemsSource="{Binding Orders}" />
this.sfDataGrid.AddNewRowPosition = AddNewRowPosition.Top;
this.sfDataGrid.AddNewRowText = "Click here to add new row in datagrid";
Customize the newly added row position
SfDataGrid adds new data item from AddNewRow at the end of collection. When data operations (sorting, grouping) performed, the new item added based on data operations. You can customize the newly added data item position by setting SfDataGrid.NewItemPlaceHolderPosition.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AddNewRowPosition="Top"
NewItemPlaceholderPosition="AtBeginning"
ItemsSource="{Binding Orders}">
this.sfDataGrid.AddNewRowPosition = AddNewRowPosition.Top;
this.sfDataGrid.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;
Initializing default values for AddNewRow
SfDataGrid allows you to set the default values for AddNewRow while initiating, through AddNewRowInitiatingEventArgs.NewObject property in SfDataGrid.AddNewRowInitiating event.
this.sfDataGrid.AddNewRowInitiating += SfDataGrid_AddNewRowInitiating;
void SfDataGrid_AddNewRowInitiating(object sender, AddNewRowInitiatingEventArgs e)
{
var orderInfo = e.NewObject as OrderInfo;
orderInfo.OrderID = 101;
}
Working with complex properties in AddNewRow
SfDataGrid control does not initiate values for complex properties defined in the data object. Hence, you need to initiate the default values for the complex properties externally by using the SfDataGrid.AddNewRowInitiating
event.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AddNewRowInitiating="SfDataGrid_AddNewRowInitiating"
AutoGenerateColumns="False"
ItemsSource="{Binding Orders}">
<dataGrid:SfDataGrid.Columns>
<dataGrid:GridTextColumn MappingName="OrderID" />
<dataGrid:GridTextColumn MappingName="Customer.CustomerID" />
<dataGrid:GridTextColumn MappingName="ShipCity" />
</dataGrid:SfDataGrid.Columns>
</dataGrid:SfDataGrid>
this.sfDataGrid.AddNewRowInitiating += SfDataGrid_AddNewRowInitiating;
private void SfDataGrid_AddNewRowInitiating(object sender, AddNewRowInitiatingEventArgs e)
{
var orderInfo = e.NewObject as OrderInfo;
orderInfo.Customer = new Customer();
}
Validating AddNewRow
You can validate the data in AddNewRow like other data rows through built-in validation or custom validation. Here, AddNewRow is validated using RowValidating event by setting RowValidatingEventArgs.IsValid to false
which doesn’t allow users to commit the AddNewRow until the validation gets succeeded.
this.sfDataGrid.RowValidating += SfDataGrid_RowValidating;
private void SfDataGrid_RowValidating(object sender, RowValidatingEventArgs e)
{
if (this.sfDataGrid.IsAddNewIndex(e.RowIndex))
{
var orderInfo = e.RowData as OrderInfo;
if (orderInfo.OrderID >= 1010)
{
e.IsValid = false;
e.ErrorMessages.Add("OrderID", "OrderID should not exceed 1010.");
}
}
}
Similarly, you can validate the cells in AddNewRow by using the CurrentCellValidating event.
Customizing AddNewRow text using default resource file
SfDataGrid enables you to customize the watermark text of AddNewRow by changing value of AddNewRowText in Resource Designer. For more information, you can refer Editing default culture resource section.
To customize the AddNewRowText, add the default Syncfusion.Grid.WinUI.resw file in Resources folder and then customize the value of AddNewRowText. Refer here to learn more about localization.
Customizing AddNewRow text using style
You can customize the watermark text of AddNewRow by editing the style of AddNewRowControl
and change the content of PART_AddNewRowTextBorder’s ContentPresenter
.
xmlns:dataGrid="using:Syncfusion.UI.Xaml.DataGrid"
<Application.Resources>
<Style TargetType="dataGrid:AddNewRowControl">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="dataGrid:AddNewRowControl">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AddNewRowStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Edit">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="WM_TextBorder" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="BorderStates">
<VisualState x:Name="NormalRow" />
<VisualState x:Name="FooterRow">
<Storyboard BeginTime="0">
<ObjectAnimationUsingKeyFrames BeginTime="0"
Duration="1"
Storyboard.TargetName="PART_AddNewRowBorder"
Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0" Value="0, 1, 0, 0" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="0"
Duration="1"
Storyboard.TargetName="PART_AddNewRowBorder"
Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="0, -1, 0, 0" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="PART_CurrentFocusRow"
Margin="{TemplateBinding CurrentFocusBorderMargin}"
Stroke="#66000000"
StrokeDashArray="3,3"
StrokeThickness="1"
Visibility="{TemplateBinding CurrentFocusRowVisibility}" />
<Border x:Name="PART_RowSelectionBorder"
Background="{TemplateBinding SelectionBackground}"
Visibility="{TemplateBinding SelectionBorderVisibility}" />
<Border x:Name="PART_AddNewRowBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter />
</Border>
<Border x:Name="WM_TextBorder"
Background="#FFE6E6E6"
BorderBrush="Transparent"
BorderThickness="0,0,1,1"
IsHitTestVisible="False">
<ContentPresenter Margin="{TemplateBinding TextMargin}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="Add New Row"
FontSize="16"
BorderBrush="Gray"
FontWeight="Light"
Foreground="Red" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
AddNewRow support in Master-Details View
You can enable the AddNewRow in DetailsViewDataGrid
by specifying the position to SfDataGrid.AddNewRowPosition property in ViewDefinition.DataGrid.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AutoGenerateColumns="True"
AutoGenerateRelations="False"
ItemsSource="{Binding Orders}">
<dataGrid:SfDataGrid.DetailsViewDefinition>
<dataGrid:GridViewDefinition RelationalColumn="OrderDetails">
<dataGrid:GridViewDefinition.DataGrid>
<dataGrid:SfDataGrid x:Name="firstLevelNestedGrid"
AddNewRowPosition="Top"
AutoGenerateColumns="True" />
</dataGrid:GridViewDefinition.DataGrid>
</dataGrid:GridViewDefinition>
</dataGrid:SfDataGrid.DetailsViewDefinition>
</dataGrid:SfDataGrid>
this.firstLevelNestedGrid.AddNewRowPosition = AddNewRowPosition.Top;
Similarly, you can wire AddNewRowInitiating event for ViewDefinition.DataGrid
.
this.firstLevelNestedGrid.AddNewRowInitiating += FirstLevelNestedGrid_AddNewRowInitiating;
void FirstLevelNestedGrid_AddNewRowInitiating(object sender, AddNewRowInitiatingEventArgs args)
{
}
For auto-generated relation (when the AutoGenerateRelations is set to true
), the AddNewRow can be enabled by specifying the position to AddNewRowPosition
property in AutoGeneratingRelations
event.
this.sfDataGrid.AutoGeneratingRelations += SfDataGrid_AutoGeneratingRelations;
void SfDataGrid_AutoGeneratingRelations(object sender, AutoGeneratingRelationsArgs e)
{
e.GridViewDefinition.DataGrid.AddNewRowPosition = AddNewRowPosition.Top;
}
In the same way, you can wire AddNewRowInitiating event in the AutoGeneratingRelations
event.
this.sfDataGrid.AutoGeneratingRelations += SfDataGrid_AutoGeneratingRelations;
void SfDataGrid_AutoGeneratingRelations(object sender, AutoGeneratingRelationsArgs e)
{
e.GridViewDefinition.DataGrid.AddNewRowInitiating += DataGrid_AddNewRowInitiating;
}
void DataGrid_AddNewRowInitiating(object sender, AddNewRowInitiatingEventArgs e)
{
}
Changing the AddNewRow default text in details view grid
You can change the default static string of AddNewRow in details view grid by using the SfDataGrid.AddNewRowText property in ViewDefinition.DataGrid
. The AddNewRowText
property has higher priority than the text that is localized in resx file.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AutoGenerateColumns="True"
AutoGenerateRelations="False"
ItemsSource="{Binding Orders}">
<dataGrid:SfDataGrid.DetailsViewDefinition>
<dataGrid:GridViewDefinition RelationalColumn="OrderDetails">
<dataGrid:GridViewDefinition.DataGrid>
<dataGrid:SfDataGrid x:Name="firstLevelNestedGrid"
AddNewRowPosition="Top"
AddNewRowText="Click here to add new row in child grid"
AutoGenerateColumns="True" />
</dataGrid:GridViewDefinition.DataGrid>
</dataGrid:GridViewDefinition>
</dataGrid:SfDataGrid.DetailsViewDefinition>
</dataGrid:SfDataGrid>
this.firstLevelNestedGrid.AddNewRowPosition = AddNewRowPosition.Top;
this.firstLevelNestedGrid.AddNewRowText = "Click here to add new row in child grid";
Delete row
DataGrid provides built-in support to delete the selected records in user interface (UI) by pressing Delete key. You can enable the deleting support by setting the SfDataGrid.AllowDeleting property to true
. AllowDeleting
is only supported when SelectionUnit is Row.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AllowDeleting="True"
AutoGenerateColumns="True"
ItemsSource="{Binding Orders}" />
this.sfDataGrid.AllowDeleting = true;
You can delete record directly in underlying collection also using Remove () or RemoveAt (int index).
(sfDataGrid.DataContext as ViewModel).Orders.Remove(sfDataGrid.CurrentItem as OrderInfo);
// OR
(sfDataGrid.DataContext as ViewModel).Orders.RemoveAt(2);
Events
RecordDeleting
RecordDeleting event occurs when the record is being deleted from SfDataGrid. The RecordDeletingEventArgs provides information to RecordDeleting
event for deleting the record and it contains the following members.
-
Cancel - Gets or sets a value indicating whether the event should be canceled.
-
OriginalSender - Gets the original sender from where the event is raised.
-
Items - Gets or sets the items to be removed from the source collection.
You can cancel the delete operation through Cancel
property in RecordDeleting
event.
this.sfDataGrid.RecordDeleting += SfDataGrid_RecordDeleting;
private void SfDataGrid_RecordDeleting(object sender, RecordDeletingEventArgs e)
{
var item = e.Items[0] as OrderInfo;
if (item.OrderID == 1005)
{
e.Cancel = true;
}
}
RecordDeleted
RecordDeleted event occurs after the record is deleted. The RecordDeletedEventArgs of RecordDeleted
event contains the following members.
-
Items - Gets the records that were removed from the source collection.
-
SelectedIndex - Gets or sets the selected index for the SfDataGrid control.
Handling selection after deleting the record from SfDataGrid
You can handle the selection after remove the records through SelectedIndex
property of RecordDeleted
event.
this.sfDataGrid.RecordDeleted += SfDataGrid_RecordDeleted
private void SfDataGrid_RecordDeleted(object sender, RecordDeletedEventArgs e)
{
e.SelectedIndex = -1;
}
Deleting cell value in display mode
By default, the cell content can be cleared in edit mode by pressing Delete or Backspace key. It is also possible to delete the cell when it’s not in edit mode by handling the Delete key operation in the ProcessKeyDown method of GridSelectionController or GridCellSelectionController. Based on type of SelectionUnit
, override right selection controller.
this.sfDataGrid.SelectionController = new GridSelectionControllerExt(sfDataGrid);
public class GridSelectionControllerExt : GridSelectionController
{
public GridSelectionControllerExt(SfDataGrid dataGrid) : base(dataGrid)
{
}
protected override void ProcessKeyDown(KeyRoutedEventArgs args)
{
//Customizes the Delete key operation.
if (args.Key == VirtualKey.Delete)
{
//Gets the cell value of current column.
var record = this.DataGrid.CurrentItem;
var currentColumnIndex = this.CurrentCellManager.CurrentCell.ColumnIndex;
var columnIndex = this.DataGrid.ResolveToGridVisibleColumnIndex(currentColumnIndex);
var mappingName = this.DataGrid.Columns[columnIndex].MappingName;
var cellVal = this.DataGrid.View.GetPropertyAccessProvider().GetValue(record, mappingName);
//Returns the cell value when the current column's cell is not set to null.
if (cellVal != null)
{
PropertyInfoExtensions.SetValue(this.DataGrid.View.GetItemProperties(), record, null, mappingName);
}
}
else
base.ProcessKeyDown(args);
}
}
Conditionally deleting records when pressing Delete key
You can cancel the record deletion by using the RecordDeletingEventArgs.Cancel
of RecordDeleting
event. You can skip certain records when deleting more than one record by removing items from RecordDeletingEventArgs.Items
.
this.sfDataGrid.RecordDeleting += SfDataGrid_RecordDeleting;
private void SfDataGrid_RecordDeleting(object sender, RecordDeletingEventArgs e)
{
foreach (var item in e.Items)
{
if ((item as OrderInfo).OrderID == 1001)
{
e.Cancel = true;
}
}
}