Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 81 additions & 65 deletions blazor/common/data-binding/data-updates.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,84 @@
---
layout: post
title: ObservableCollection and INotifyPropertyChanged in Syncfusion Blazor
description: Learn how Syncfusion Blazor components react to changes from ObservableCollection and INotifyPropertyChanged without manual refresh. Explore to more details.
description: Learn how Syncfusion Blazor components automatically update with ObservableCollection and INotifyPropertyChanged, eliminating manual refresh.
platform: Blazor
component: Common
documentation: ug
---

# Data updates with Interface

Syncfusion<sup style="font-size:70%">&reg;</sup> Blazor components automatically update UI when bound data implements `INotifyCollectionChanged` (`ObservableCollection`) or `INotifyPropertyChanged`.
Syncfusion<sup style="font-size:70%">&reg;</sup> Blazor components provide automatic UI updates when the bound data source uses `ObservableCollection` and implements [INotifyCollectionChanged](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.inotifycollectionchanged?view=net-10.0) or [INotifyPropertyChanged](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged?view=net-10.0). These interfaces enable real-time synchronization between the data model and the component without requiring explicit refresh calls.

## ObservableCollection
**Key Difference:**

- Use `ObservableCollection` with `INotifyCollectionChanged` for **collection-level changes** such as adding or removing items.
- Use `INotifyPropertyChanged` for **property-level changes** within individual items, such as updating an existing record.

Data-bound components (such as DataGrid, Kanban, Scheduler) provides support to update its data without any additional refresh call when using `ObservableCollection` as data source and perform add, remove, clear actions in collection. ObservableCollection notifies the collection changes using [INotifyCollectionChanged](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.inotifycollectionchanged) interface.
## ObservableCollection

In the following example, the DataGrid updates automatically when items are added to or removed from the `ObservableCollection`.
Data-bound components such as `DataGrid`, `Kanban`, and `Scheduler` support automatic UI updates when an `ObservableCollection` is used as the data source. These components handle operations like **Add**, **Remove**, and **Clear** performed on the collection without requiring additional refresh calls. `ObservableCollection` achieves this by implementing the [INotifyCollectionChanged](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.inotifycollectionchanged) interface, which raises notifications whenever the collection is modified.

```cshtml
@using System.Collections.ObjectModel;
@using System.Collections.ObjectModel
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.Buttons

<SfButton ID="add" @onclick="AddRecord">Add Record</SfButton>
<SfButton ID="del" CssClass="deleteBtn" @onclick="DeleteRecord">Delete Record</SfButton>
<br /><br />
<SfGrid DataSource="@observableData" AllowPaging="true">
<GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true"></GridEditSettings>
<SfButton OnClick="AddRecord">Add Record</SfButton>
<SfButton OnClick="DeleteRecord">Delete Record</SfButton>

<SfGrid DataSource="@observableData">
<GridColumns>
<GridColumn Field=@nameof(DataOrder.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="@TextAlign.Center" HeaderTextAlign="@TextAlign.Center" Width="140"></GridColumn>
<GridColumn Field=@nameof(DataOrder.CustomerName) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(DataOrder.Freight) HeaderText="Freight" EditType="EditType.NumericEdit" Format="C2" Width="140" TextAlign="@TextAlign.Right" HeaderTextAlign="@TextAlign.Right"></GridColumn>
<GridColumn Field=@nameof(DataOrder.OrderDate) HeaderText="Order Date" EditType="EditType.DatePickerEdit" Format="d" TextAlign="TextAlign.Right" Type="ColumnType.Date" Width="160"></GridColumn>
<GridColumn Field="OrderID" HeaderText="Order ID" Width="120"></GridColumn>
<GridColumn Field="CustomerName" HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field="Freight" HeaderText="Freight" Width="100" Format="C2"></GridColumn>
<GridColumn Field="OrderDate" HeaderText="Order Date" Width="150" Format="d"></GridColumn>
</GridColumns>
</SfGrid>

@code{
private ObservableCollection<DataOrder> observableData { get; set; }
@code {

private ObservableCollection<DataOrder> observableData = new ObservableCollection<DataOrder>();

private int uniqueId;

protected override void OnInitialized()
{
observableData = new ObservableCollection<DataOrder>(Enumerable.Range(1, 5).Select(x => new DataOrder()
{
OrderID = 10000 + x,
CustomerName = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)],
Freight = 2.1 * x,
OrderDate = DateTime.Now.AddDays(-x),
}));
observableData = new ObservableCollection<DataOrder>(
Enumerable.Range(1, 5).Select(x => new DataOrder
{
OrderID = 10000 + x,
CustomerName = new[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" }[new Random().Next(5)],
Freight = 2.1 * x,
OrderDate = DateTime.Now.AddDays(-x)
})
);
}

private void AddRecord()
{
observableData.Add(new DataOrder() { OrderID = 10010 + ++uniqueId, CustomerName = "VINET", Freight = 30.35, OrderDate = new DateTime(1991, 05, 15) });
observableData.Add(new DataOrder
{
OrderID = 10010 + ++uniqueId,
CustomerName = "VINET",
Freight = 30.35,
OrderDate = new DateTime(1991, 05, 15)
});
}

private void DeleteRecord()
{
if (observableData.Count() != 0)
if (observableData.Count > 0)
{
observableData.Remove(observableData.First());
}
}

public class DataOrder
private class DataOrder
{
public int OrderID { get; set; }
public string CustomerName { get; set; }
public string? CustomerName { get; set; }
public DateTime OrderDate { get; set; }
public double Freight { get; set; }
}
Expand Down Expand Up @@ -104,75 +116,79 @@ In the following example, the DataGrid updates automatically when items are adde

## INotifyPropertyChanged

Data-bound components (such as DataGrid, Kanban, and Scheduler) provides support to update its data without any additional refresh call when changing property value of item if an item implements [INotifyPropertyChanged ](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged) interface. `INotifyPropertyChanged` interface is used to notify, that a property value has changed.

In the following example, the `DataOrder` type implements `INotifyPropertyChanged` and raises the [PropertyChanged](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged.propertychanged) event when a property value changes. DataGrid automatically updates its property values are changed in data object by listening to `PropertyChanged` event.
Data-bound components such as `DataGrid`, `Kanban`, and `Scheduler` automatically refresh the UI when the underlying data type implements [INotifyPropertyChanged](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged). The interface raises the [PropertyChanged](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged.propertychanged?view=net-10.0) event whenever a property value changes, allowing the component to re-render without an explicit refresh call.

```cshtml
@using System.Collections.ObjectModel;
@using System.ComponentModel;
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Grids;
@using Syncfusion.Blazor.Buttons;

<SfButton OnClick="UpdateRecord">Update Data</SfButton>

<SfButton ID="update" @onclick="UpdateRecord">Update Data</SfButton>
<br /><br />
<SfGrid DataSource="@observableData" AllowPaging="true">
<GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true"></GridEditSettings>
<SfGrid DataSource="@observableData">
<GridColumns>
<GridColumn Field=@nameof(DataOrder.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="@TextAlign.Center" HeaderTextAlign="@TextAlign.Center" Width="140"></GridColumn>
<GridColumn Field=@nameof(DataOrder.CustomerName) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(DataOrder.Freight) HeaderText="Freight" EditType="EditType.NumericEdit" Format="C2" Width="140" TextAlign="@TextAlign.Right" HeaderTextAlign="@TextAlign.Right"></GridColumn>
<GridColumn Field=@nameof(DataOrder.OrderDate) HeaderText="Order Date" EditType="EditType.DatePickerEdit" Format="d" TextAlign="TextAlign.Right" Type="ColumnType.Date" Width="160"></GridColumn>
<GridColumn Field="OrderID" HeaderText="Order ID" Width="120"></GridColumn>
<GridColumn Field="CustomerName" HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field="Freight" HeaderText="Freight" Width="100" Format="C2"></GridColumn>
<GridColumn Field="OrderDate" HeaderText="Order Date" Width="150" Format="d"></GridColumn>
</GridColumns>
</SfGrid>

@code{
private ObservableCollection<DataOrder> observableData { get; set; }
@code {

private ObservableCollection<DataOrder> observableData = new ObservableCollection<DataOrder>();
private int uniqueId;

protected override void OnInitialized()
{
observableData = new ObservableCollection<DataOrder>(Enumerable.Range(1, 5).Select(x => new DataOrder()
{
OrderID = 10000 + x,
CustomerName = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)],
Freight = 2.1 * x,
OrderDate = DateTime.Now.AddDays(-x),
}));
observableData = new ObservableCollection<DataOrder>(
Enumerable.Range(1, 5).Select(x => new DataOrder
{
OrderID = 10000 + x,
CustomerName = new[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" }[new Random().Next(5)],
Freight = 2.1 * x,
OrderDate = DateTime.Now.AddDays(-x)
})
);
}

private void UpdateRecord()
{
if (observableData.Count() != 0)
if (observableData.Count > 0)
{
var name = observableData.First();
name.CustomerName = "Record Updated";
var firstRecord = observableData.First();
firstRecord.CustomerName = "Record Updated";
}
}

public class DataOrder : INotifyPropertyChanged
private class DataOrder : INotifyPropertyChanged
{
public int OrderID { get; set; }
private string customerID { get; set; }
public string CustomerName
private string? customerName;

public string? CustomerName
{
get { return customerID; }
get => customerName;
set
{
this.customerID = value;
NotifyPropertyChanged("CustomerID");
if (customerName != value)
{
customerName = value;
NotifyPropertyChanged(nameof(CustomerName));
}
}
}

public DateTime OrderDate { get; set; }
public double Freight { get; set; }
public event PropertyChangedEventHandler PropertyChanged;

public event PropertyChangedEventHandler? PropertyChanged;

private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
```
```
Loading