Data Binding in MAUI DataGrid (SfDataGrid)

7 Jul 202615 minutes to read

The .NET MAUI DataGrid Control is bound to an external data source to display the data in a tabular format. It supports data sources such as List, IEnumerable, and so on. The SfDataGrid.ItemsSource property helps to bind this control with a collection of objects.

The code below demonstrates how to bind a data source to the SfDataGrid. Each row in the SfDataGrid binds to an object in the data source. Each column binds to a property in the data model object.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:GettingStarted"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.DataGrid;assembly=Syncfusion.Maui.DataGrid"
             x:Class="GettingStarted.MainPage">

    <ContentPage.BindingContext>
        <local:OrderInfoViewModel/>
    </ContentPage.BindingContext>

    <syncfusion:SfDataGrid x:Name="dataGrid"
                       ItemsSource="{Binding OrderInfoCollection}" />
</ContentPage>
OrderInfoViewModel orderInfoViewModel = new OrderInfoViewModel();
SfDataGrid dataGrid = new SfDataGrid();
dataGrid.ItemsSource = orderInfoViewModel.OrderInfoCollection;

If the data source implements the INotifyCollectionChanged interface, then the SfDataGrid will automatically refresh the view when an item is added, removed, or cleared. ObservableCollection implements this interface and automatically triggers UI updates. However, List does not, so changes will not refresh the view automatically.

If the data model implements the INotifyPropertyChanged interface, then the SfDataGrid responds to property changes at runtime and updates the view.

Binding with IEnumerable

The SfDataGrid control supports binding any collection that implements from IEnumerable interface. All the data operations such as sorting and filtering are supported when the binding collection is derived from IEnumerable.

Binding with DataTable

The SfDataGrid control supports binding to a DataTable. The SfDataGrid automatically refreshes the UI when rows are added, removed, or cleared.

DataTable table = GetDataTable();
SfDataGrid dataGrid = new SfDataGrid();
dataGrid.ItemsSource = table;

private DataTable GetDataTable()
{
    DataTable table = new DataTable("Orders");
    table.Columns.Add("OrderID", typeof(int));
    table.Columns.Add("CustomerName", typeof(string));
    table.Columns.Add("OrderDate", typeof(DateTime));
    
    table.Rows.Add(1001, "John Smith", new DateTime(2024, 1, 15));
    table.Rows.Add(1002, "Jane Doe", new DateTime(2024, 1, 16));
    table.Rows.Add(1003, "Bob Wilson", new DateTime(2024, 1, 17));
    
    return table;
}

Limitations

Binding with dynamic data object

The SfDataGrid control supports binding to dynamic data objects using ExpandoObject.

Example: ViewModel with Dynamic Objects

using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Runtime.CompilerServices;

public class EmployeeViewModel : INotifyPropertyChanged
{
    private ObservableCollection<dynamic> _employeeDetails;
    private readonly Random _random = new Random();
    private readonly string[] _employeeNames = new[]
    {
        "Sean Jacobson",
        "Phyllis Allen",
        "Marvin Allen",
        "Michael Allen",
    };
    
    public EmployeeViewModel()
    {
        EmployeeDetails = GetEmployeesDetails_Dynamic(200);
    }
    
    public ObservableCollection<dynamic> EmployeeDetails
    {
        get => _employeeDetails;
        set
        {
            if (_employeeDetails != value)
            {
                _employeeDetails = value;
                OnPropertyChanged();
            }
        }
    }
    
    public ObservableCollection<dynamic> GetEmployeesDetails_Dynamic(int count)
    {
        var employees = new ObservableCollection<dynamic>();
        for (int i = 1; i <= count; i++)
        {
            employees.Add(GetDynamicEmployee(i));
        }
        return employees;
    }
    
    public dynamic GetDynamicEmployee(int id)
    {
        dynamic employee = new ExpandoObject();
        employee.EmployeeID = id;
        employee.EmployeeName = _employeeNames[_random.Next(_employeeNames.Length)];
        employee.ContactID = id + 1000;
        return employee;
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Manually Defined Columns (with Dynamic Data)

<syncfusion:SfDataGrid x:Name="dataGrid"
                       ItemsSource="{Binding EmployeeDetails}"
                       AutoGenerateColumnsMode="None">
    <syncfusion:SfDataGrid.Columns>
        <syncfusion:DataGridNumericColumn MappingName="[EmployeeID]"
                                          HeaderText="Employee ID" />
        <syncfusion:DataGridTextColumn MappingName="[EmployeeName]"
                                       HeaderText="Employee Name" />
        <syncfusion:DataGridNumericColumn MappingName="[ContactID]"
                                          HeaderText="Contact ID" />
    </syncfusion:SfDataGrid.Columns>
</syncfusion:SfDataGrid>
<syncfusion:SfDataGrid x:Name="dataGrid"
                       ItemsSource="{Binding OrderInfoCollection}"
                       AutoGeneratingColumn="datagrid_AutoGeneratingColumn" />
OrderInfoRepository viewModel = new OrderInfoRepository();

SfDataGrid dataGrid = new SfDataGrid();
dataGrid.ItemsSource = viewModel.OrderInfoCollection;
dataGrid.AutoGeneratingColumn += datagrid_AutoGeneratingColumn;

private void datagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
     e.Column.MappingName = "[" + e.Column.MappingName + "]";
}

Limitations with Dynamic Objects

  • SfDataGrid doesn’t support LiveDataUpdateMode with AllowDataShaping and AllowSummaryUpdate.

Binding complex properties

The SfDataGrid control supports binding complex (nested) properties to columns. To bind a complex property, set the property path to MappingName using dot notation.

Data Model Example

public class OrderInfo
{
    public int OrderID { get; set; }
    public string ShipCity { get; set; }
    public Customer Customer { get; set; }
}

public class Customer
{
    public string CustomerID { get; set; }
    public string CustomerName { get; set; }
}

XAML Example

<syncfusion:SfDataGrid AutoGenerateColumnsMode="None"
                       ItemsSource="{Binding OrderInfoCollection}">
    <syncfusion:SfDataGrid.Columns>
        <syncfusion:DataGridNumericColumn MappingName="OrderID" HeaderText="Order ID" />
        <syncfusion:DataGridTextColumn MappingName="Customer.CustomerID" HeaderText="Customer ID" />
        <syncfusion:DataGridTextColumn MappingName="Customer.CustomerName" HeaderText="Customer Name" />
        <syncfusion:DataGridTextColumn MappingName="ShipCity" HeaderText="City" />
    </syncfusion:SfDataGrid.Columns>
</syncfusion:SfDataGrid>

The SfDataGrid control provides support for binding complex properties such as indexers, dictionaries to its columns. To bind the complex property to DataGridColumn, set the UseBindingValue property to true.

<syncfusion:SfDataGrid AutoGenerateColumnsMode="None"
                       ItemsSource="{Binding OrderInfoCollection}">
    <syncfusion:SfDataGrid.Columns>
        <syncfusion:DataGridTextColumn MappingName="OrderID" UseBindingValue="True" />
        <syncfusion:DataGridTextColumn MappingName="CustomerID" UseBindingValue="True" />
        <syncfusion:DataGridTextColumn MappingName="ShipCity" UseBindingValue="True" />
    </syncfusion:SfDataGrid.Columns>
</syncfusion:SfDataGrid>

Limitations when binding complex property

  • SfDataGrid doesn’t support LiveDataUpdateMode - AllowDataShaping and AllowSummaryUpdate.

View and Data Operations

When you bind a collection to the ItemsSource property, the SfDataGrid creates a view object that manages data operations.

ICollectionViewAdv Interface

The ICollectionViewAdv interface is responsible for:

  • Maintaining the collection and applying filters/sorts
  • Handling data insertions, deletions, and modifications
  • Supporting advanced operations like grouping and summaries

The SfDataGrid creates different view implementations based on your ItemsSource type.

LiveDataUpdateMode

During data manipulation operations and property changes, the SfDataGrid supports updating the view by using the LiveDataUpdateMode property which exists in the SfDataGrid.View class.

LiveDataUpdateMode Description
Default Data operations are not updated.
AllowSummaryUpdate Summaries are updated during data manipulation change.
AllowDataShaping Data operations like sorting, and filtering are updated during data manipulation change.
SfDataGrid dataGrid = new SfDataGrid();
dataGrid.Loaded += SfDataGrid_Loaded;

private void SfDataGrid_Loaded(object sender, EventArgs e)
{
    dataGrid.View.LiveDataUpdateMode = LiveDataUpdateMode.Default;
}

RecordPropertyChanged Event

The RecordPropertyChanged event fires when a data model property changes (requires INotifyPropertyChanged implementation).

Event Arguments

  • sender: The data model object
  • PropertyChangedEventArgs.PropertyName: Name of the changed property

Example

  • C#
  • void OnViewLoaded()
    {
        dataGrid.View.RecordPropertyChanged += (sender, args) =>
        {
            Debug.WriteLine($"Property changed: {args.PropertyName}");
        };
    }

    SourceCollectionChanged Event

    The SourceCollectionChanged event fires when the underlying collection is modified (add, remove, clear items).

    Event Arguments (NotifyCollectionChangedEventArgs)

    • Action: Type of change (Add, Remove, Move, Replace, or Reset)
    • NewItems: Items added to the collection
    • OldItems: Items removed from the collection
    • NewStartingIndex: Index where new items appear
    • OldStartingIndex: Index where old items were

    Example

  • C#
  • void OnViewLoaded()
    {
        dataGrid.View.SourceCollectionChanged += (sender, args) =>
        {
            if (args.Action == NotifyCollectionChangedAction.Add)
                Debug.WriteLine($"{args.NewItems.Count} items added at index {args.NewStartingIndex}");
        };
    }

    Retain scroll position

    To retain the scroll position when ItemsSource changes, set the SfDataGrid.CanMaintainScrollPosition to true. If you set SfDataGrid.CanMaintainScrollPosition to true then on changing ItemsSource, the newly added ItemsSource will be loaded with the previous ItemsSource’s ScrollOffset.

  • C#
  • SfDataGrid dataGrid = new SfDataGrid();
    dataGrid.CanMaintainScrollPosition = true;

    SetCellValue

    The SetCellValue method allows you to programmatically update a cell value at runtime.

    Note: For features like Sorting, Grouping, or Filtering to update automatically after a value change, set LiveDataUpdateMode="AllowDataShaping" on the grid’s View. Ensure the cell’s row and column exist in the grid.

    Limitations

    • Caption rows, summary rows, unbound rows, and unbound columns cannot be updated by SetCellValue.

    SfDataGrid provides two overloads of SetCellValue:

    1. SetCellValue(int rowIndex, DataGridColumn column, object value)
    Parameter Type Description
    rowIndex int The index of the row in which the cell exists.
    column DataGridColumn It represents the column of the cell to be updated.
    value object The new value to assign to the cell.
    private void Button_Clicked(object sender, EventArgs e)
    {
        // Update using column object
        dataGrid.SetCellValue(1, dataGrid.Columns[0], "11111");    
    }

    Overload 2: SetCellValue(int rowIndex, string fieldName, object value)

    Parameter Type Description
    rowIndex int The index of the row in which the cell exists.
    column string fieldName The name of the property to update in the data record.
    value object The new value to assign to the cell.
    private void Button_Clicked(object sender, EventArgs e)
    {
        // Update using property name
        dataGrid.SetCellValue(1, "OrderID", "11111");    
    }

    Note: Looking for the full .NET MAUI DataGrid component overview, features, pricing, and documentation? Visit the .NET MAUI DataGrid page.