Skip to content

Cells

Cells in a Grid control are used to display and edit row values. They are formed at the intersections of rows and columns. While cells present the data, their behavior and appearance (for example, in-place editors and formatting settings) are usually defined by the properties of their parent columns. This topic summarizes how to manage and obtain cell content and to customize cell appearance.

Format Cell Values

The Data Grid control allows you present cell values using common and custom formats. For instance, you can format numeric values as a currency, a percentage, an integer or float number, and so on. A DateTime value can be presented in a short date format, long date format, only time format, etc.

The following approaches are available to format cell values:

Use Masked Input

Eremex editors allow you to use masks to restrict data input and format numeric and date-time values. Masks are supported both for standalone editors and editors embedded in container controls (DataGrid, TreeList, PropertyGrid, and so on).

Applicable to: Cells in display and edit mode. To prevent masks from being applied in display mode (when cell editing is not active), disable the editor's MaskUseAsDisplayFormat property.

Steps:

  1. Assign an Eremex in-place editor to a column.
  2. Set the editor's MaskType property to MaskType.Numeric or MaskType.DateTime to apply a mask to numeric or date-time values, respectively.
  3. Set the editor's Mask property to the required mask. See the following topics for information on mask specifiers:

Example - Custom Format Date-time Values Using Masks

The following example assigns a DateEditor to a column, and applies a custom date-time mask ("MMMM dd, yyyy"). This mask formats cell values in edit and display mode, as shown in the image below:

cells-formatting-masks-customdatetime

<mxdg:GridColumn FieldName="BirthDate" Width="*" MinWidth="80">
    <mxdg:GridColumn.EditorProperties>
        <mxe:DateEditorProperties MaskType="DateTime" Mask="MMMM dd, yyyy"/>
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

Set a Display Format

You can use standard and custom format specifiers to format cell values in display mode.

Applicable to: Cells in display mode.

Drawbacks: Display formats are not applied in edit mode, nor do they restrict user input. For example, users still able to enter letters in numeric columns that use text editors. To format values in display and edit modes and to restrict data input, use dedicated editors (SpinEditor for numeric values, DateEditor for date-time values) or apply masks to your text editor.

Steps:

  1. Assign an Eremex in-place editor to a column.
  2. Set the editor's display format using its DisplayFormatString property.
  3. For editors that use masks for display value formatting, disable the editor's MaskUseAsDisplayFormat property. For example, DateEditor and SpinEditor use masks for value formatting in display mode, by default. So, disabling the MaskUseAsDisplayFormat property is required for these editors to apply the display format specified by the DisplayFormatString property.

    You can find the description of all display formats in the .NET documentation:

Example - Format Date-Time Values Differently in Display and Edit Modes

The following example assigns a DateEditor in-place editor to a column, and uses its settings to apply different value formatting in display and edit modes:

  • The DisplayFormatString property is set to 'd'. This setting applies the short date format to values in display mode. For the DisplayFormatString property to be in effect, the MaskUseAsDisplayFormat property is disabled.
  • The Mask property is set to 'g'. This format enables the full date-time pattern with long time in edit mode.

cells-formatting-displayformat-dateeditors-example

<mxdg:GridColumn FieldName="OrderDate" Width="3*" BandName="AdditionalInformation" >
    <mxdg:GridColumn.EditorProperties>
        <mxe:DateEditorProperties DisplayFormatString="d" Mask="g" MaskUseAsDisplayFormat="False" />
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

Example - Format Values as Currency

The following example assigns a TextEditor in-place editor to a column, and sets the editor's DisplayFormatString property to the "c" string. This format displays cell values as a currency when cells are in display mode:

cells-formatting-currencyexample

<mxdg:GridColumn FieldName="Price" Width="2*">
    <mxdg:GridColumn.EditorProperties>
        <mxe:TextEditorProperties DisplayFormatString="c" />
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

Example - Custom Format Float Values

The code below assigns a TextEditor in-place editor to a column, and sets the DisplayFormatString property to the "{}{0:F1} kW" string. This format displays float values with one digit after the decimal point, and adds the "kW" suffix to the output. When a cell is in edit mode, the display format is not applied. The "{}" string is an escape token that allows the XAML parser to treat a string starting with an open curly brace ("{") as literal text rather than a markup extension.

cells-formatting-float-customformatting

<mxdg:GridColumn FieldName="PowerConsumption" Width="1.2*" >
    <mxdg:GridColumn.EditorProperties>
        <mxe:TextEditorProperties DisplayFormatString="{}{0:F1} kW" />
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

Format Display Values Using an Event

Applicable to: Cells in display mode

If no display format or mask meets your requirements, you can handle the CustomColumnDisplayText event to format cell values in a custom manner. This event allows you to replace default text representatation of values in cells and column filters. To supply custom value display text for group rows, handle the DataGridControl.CustomGroupValueDisplayText event.

When you change cell display text, underlying cell values are not modified.

Example - Custom Format Cell Values Using the CustomColumnDisplayText Event

The following CustomColumnDisplayText event handler displays the "pcs" string after cell values in the "Stock" column. Custom display values provided using this event are ignored when cells are being edited.

cells-formatting-customcolumndisplaytext-example

using Eremex.AvaloniaUI.Controls.DataGrid;

private void DataGrid_CustomColumnDisplayText(object sender, DataGridCustomColumnDisplayTextEventArgs e)
{
    if (e.Column.FieldName == "Stock")
        e.DisplayText = string.Format("{0} pcs", e.Value);
}

Value Alignment

Default horizontal content alignment in cells vary by cell data type:

  • Numeric values are aligned to the right.
  • Boolean values (check boxes) are centered.
  • Other values are aligned to the left.

Vertically cell values are centered, by default.

To custom align values in cells horizontally or vertically, do the following:

  1. Assign an Eremex in-place editor to a column.
  2. Use the editor's HorizontalContentAlignment property to set the horizontal alignment.
  3. Use the editor's VerticalContentAlignment property to set the vertical alignment.

Example - Center Column Values and Header

The following code centers values and header in the Hire Date column. To align cell values, the code assigns a DateEditorin-place editor to this column, and then sets the editor's HorizontalContentAlignment property to Center. To align the column header's content, the column's HorizontalContentAlignment property is used.

cells-value-alignment-example

<mxdg:GridColumn FieldName="HireDate" Width="*" MinWidth="80" HeaderHorizontalAlignment="Center">
    <mxdg:GridColumn.EditorProperties>
        <mxe:DateEditorProperties HorizontalContentAlignment="Center"/>
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

Multi-line Text and Text Wrapping in Cells

Do the following to display multi-line text in cells:

  1. Assign a TextEditor in-place editor (or its descendant) to a column.
  2. Use the editor's TextWrapping property to enable text wrapping.

When text wrapping is enabled, the heights of rows are automatically adjusted to display cell contents in their entirety.

Example - Enable Text Wrapping in Cells

The following code assigns a text editor to a column and enables text wrapping for this editor.

cells-multiline-text-wrapping

<mxdg:GridColumn FieldName="Notes" Width="*" MinWidth="80">
    <mxdg:GridColumn.EditorProperties>
        <mxe:TextEditorProperties TextWrapping="Wrap"/>
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

Provide Data for Cells

Cells in the DataGrid control belong to either bound or unbound columns.

Bound columns are linked to fields (properties) in the control's underlyinga data source. The GridColumn.FieldName properties of these columns are set to the field names that exist in the data source. Cells of bound columns get their values from corresponding data source fields.

Unbound columns (also called calculated columns) allow you to display (and optionally edit) values that are not present in the data source. For instance, you can create a read-only unbound column that displays values calculated from multiple other fields. Values for unbound columns are provided with the CustomUnboundColumnData event. You can also create editable unbound columns. In this case, your CustomUnboundColumnData event handler must also save data entered by users (for instance, you can save it to a cache or a data source).

Unbound columns can be used to customize display text of cells. For information on other methods for display text customization, see Customize Display Text of Cells.

Example — Create a Calculated Column

The following example creates an unbound column Year Total. The CustomUnboundColumnData event handler calculates values for this column as a sum of Quarter1, Quarter2, Quarter3 and Quarter4 fields.

cells-unbound-columns-revenue-example

<!-- MainWindow.axaml -->
xmlns:mxdg="https://schemas.eremexcontrols.net/avalonia/datagrid"
xmlns:mxe="https://schemas.eremexcontrols.net/avalonia/editors"
xmlns:sys="clr-namespace:System;assembly=System.Runtime"

<mxdg:DataGridControl Name="dataGrid1" Margin="10" BorderThickness="1"
                        ItemsSource="{Binding Revenues}"
                        CustomUnboundColumnData="dataGrid1_CustomUnboundColumnData" >
    <mxdg:DataGridControl.Columns>
        <mxdg:GridColumn FieldName="Description" Width="*" />
        <mxdg:GridColumn FieldName="Quarter1" Width="*">
            <mxdg:GridColumn.EditorProperties>
                <mxe:TextEditorProperties MaskType="Numeric" Mask="c0"/>
            </mxdg:GridColumn.EditorProperties>
        </mxdg:GridColumn>
        <mxdg:GridColumn FieldName="Quarter2" Width="*">
            <mxdg:GridColumn.EditorProperties>
                <mxe:TextEditorProperties MaskType="Numeric" Mask="c0"/>
            </mxdg:GridColumn.EditorProperties>
        </mxdg:GridColumn>
        <mxdg:GridColumn FieldName="Quarter3" Width="*">
            <mxdg:GridColumn.EditorProperties>
                <mxe:TextEditorProperties MaskType="Numeric" Mask="c0"/>
            </mxdg:GridColumn.EditorProperties>
        </mxdg:GridColumn>
        <mxdg:GridColumn FieldName="Quarter4" Width="*">
            <mxdg:GridColumn.EditorProperties>
                <mxe:TextEditorProperties MaskType="Numeric" Mask="c0"/>
            </mxdg:GridColumn.EditorProperties>
        </mxdg:GridColumn>
        <mxdg:GridColumn Name="colYearTotal" FieldName="YearTotal"
                            Width="*" ReadOnly="True" UnboundDataType="{x:Type sys:Decimal}" >
            <mxdg:GridColumn.EditorProperties>
                    <mxe:TextEditorProperties DisplayFormatString="c0"/>
                </mxdg:GridColumn.EditorProperties>
            </mxdg:GridColumn>
    </mxdg:DataGridControl.Columns>
</mxdg:DataGridControl>
// MainWindow.axaml.cs
private void dataGrid1_CustomUnboundColumnData(object? sender, DataGridUnboundColumnDataEventArgs e)
{
    if (e.IsGettingData && e.Column.FieldName == "YearTotal")
    {
        RevenueViewModel rec = e.Item as RevenueViewModel;
        if (rec != null)
        {
            e.Value = rec.Quarter1 + rec.Quarter2 + rec.Quarter3 + rec.Quarter4;
        }
    }
}
// MainWindowViewModel.cs
public partial class MainWindowViewModel : ObservableObject
{
    [ObservableProperty]
    List<RevenueViewModel> revenues;

    public MainWindowViewModel()
    {
        revenues = new List<RevenueViewModel>
            {
                new() { Description = "2025 Revenue", Quarter1 = 1250000m, Quarter2 = 1425000m, Quarter3 = 1680000m, Quarter4 = 1950000m },
                new() { Description = "2026 Revenue", Quarter1 = 1100000m, Quarter2 = 1250000m, Quarter3 = 1450000m, Quarter4 = 1750000m },
                new() { Description = "2027 Revenue", Quarter1 = 950000m, Quarter2 = 1050000m, Quarter3 = 1200000m, Quarter4 = 1400000m },
            };
    }
}

public partial class RevenueViewModel : ObservableObject
{
    [ObservableProperty]
    private string description;

    [ObservableProperty]
    private decimal quarter1;

    [ObservableProperty]
    private decimal quarter2;

    [ObservableProperty]
    private decimal quarter3;

    [ObservableProperty]
    private decimal quarter4;
}

See the following topic for more information: Unbound Columns.

Customize Display Text of Cells

You can handle the CustomColumnDisplayText event to customize display text of specific cells. This event affects only displayed text, but not cell edit values.

The CustomColumnDisplayText event also allows you to modify text representation of cell values in column filters and filter panel. When the CustomColumnDisplayText event fires for values in the filter panel, the event's SourceItemIndex parameter returns -1. To supply custom value display text for group rows, handle the DataGridControl.CustomGroupValueDisplayText event.

If cell display text is dependent of values of other data source fields/properties, you can retrieve these field values using the DataGridControl's methods (DataGridControl.GetSourceItem and DataGridControl.GetSourceItemValue) and the methods of your data source.

Example - Modify Cell Display Text Using an Event

The following example handles the CustomColumnDisplayText event to modify display text of HireDate column values.

The grid in the current example displays a collection of EmployeeInfo objects. The EmployeeInfo.HireDate field specifies a date when a person was hired. The EmployeeInfo.Experience field specifies the total number of the employee's working years. The initial layout is shown below:

cells-grid-customcolumndisplaytext-example-initial-layout

The CustomColumnDisplayText event handler provides custom display text for HireDate values. Instead of date-time values, the HireDate column will display the number of working years from the hiring date till today, followed by the total number of working years (a value of the Experience column). The captions of the HireDate and Experience columns are replaced with "Company Work Experience" and "Total Work Experience", respectively.

cells-grid-customcolumndisplaytext-example-final-layout

<!-- MainWindow.axaml -->
xmlns:data="clr-n4amespace:AppEmployees.ViewModels"
xmlns:mxdg="https://schemas.eremexcontrols.net/avalonia/datagrid"
xmlns:mxe="https://schemas.eremexcontrols.net/avalonia/editors"

<mxdg:DataGridControl x:Name="dataGrid" ItemsSource="{Binding Employees}" BorderThickness="1" Margin="10">
    <mxdg:GridColumn FieldName="FirstName" Width="*" MinWidth="80"/>
    <mxdg:GridColumn FieldName="LastName" Width="*" MinWidth="80"/>

    <mxdg:GridColumn FieldName="HireDate" Width="*" MinWidth="170" AllowEditing="False"/>
    <mxdg:GridColumn FieldName="Experience" Width="*" MinWidth="170" />

    <mxdg:GridColumn FieldName="Position" Width="*" MinWidth="100">
        <mxdg:GridColumn.EditorProperties>
            <mxe:ComboBoxEditorProperties ItemsSource="{Binding Source={x:Static data:MainWindowViewModel.Positions}}" IsTextEditable="False"/>
        </mxdg:GridColumn.EditorProperties>
    </mxdg:GridColumn>
</mxdg:DataGridControl>
// MainWindow.axaml.cs

public partial class MainWindow : MxWindow
{
    public MainWindow()
    {
        InitializeComponent();
        GridColumn colHireDate = dataGrid.Columns["HireDate"];
        GridColumn colExperience = dataGrid.Columns["Experience"];
        colExperience.Header = "Total Work Experience";
        colHireDate.Header = "Company Work Experience";
        colHireDate.ColumnFilterMode = Eremex.AvaloniaUI.Controls.DataControl.ColumnFilterMode.DisplayText;
        colHireDate.SortMode = Eremex.AvaloniaUI.Controls.DataControl.SortMode.DisplayText;
        dataGrid.CustomColumnDisplayText += DataGrid_CustomColumnDisplayText;
    }

    private void DataGrid_CustomColumnDisplayText(object sender, Eremex.AvaloniaUI.Controls.DataGrid.DataGridCustomColumnDisplayTextEventArgs e)
    {
        if (e.Column.FieldName != "HireDate")
            return;
        // Get the currently processed value of the HireDate column.
        DateTime hireDate = (DateTime)e.Value;
        // Calculate the number of days from the hire date till today.
        int workingDays = (int)(DateTime.Now - hireDate).TotalDays;
        // Calculate the number of years from the hire date till today.
        int workingYears = (int)workingDays / 365;

        // Supply custom display text for HireDate values shown in the filter panel.
        if (e.SourceItemIndex < 0)
        {
            e.DisplayText = String.Format($"{workingYears} years");
            return;
        }
        // Get the value of the Experience field.
        int totalWorkExperience = (int)dataGrid.GetSourceItemValue(e.SourceItemIndex, "Experience");
        // Supply custom display text for HireDate values.
        e.DisplayText = String.Format($"{workingYears} years ({totalWorkExperience} total)");
    }
}
using CommunityToolkit.Mvvm.ComponentModel;

public partial class MainWindowViewModel : ObservableObject
{
    [ObservableProperty]
    IList<EmployeeInfo> employees;

    public MainWindowViewModel() {
        Employees = GenerateEmployeeInfo();
    }
    //...
}
public partial class EmployeeInfo : ObservableObject
{
    [ObservableProperty]
    public string firstName;
    [ObservableProperty]
    public string lastName;
    [ObservableProperty]
    public DateTime hireDate;
    [ObservableProperty]
    public int experience;
    [ObservableProperty]
    public string position;
    [ObservableProperty]
}

Get and Set Row Values in Code

The DataGrid provides methods to get and set values in individual cells, as well as to work with underlying data objects.

Work with Cell Values

The following methods operate on cells addressed by row and column (or field name). These methods use row indexes to identify rows. Row indexes reflect the order of rows in the control, identifying both visible and hidden (within collapsed groups) rows. For more details on row identification, see: Identify and Get Rows.

Method Description
GetCellValue Returns the edit (raw) value stored in a specific cell.
SetCellValue Sets a new value in a specific cell.
GetCellDisplayText Returns the formatted display text of a cell, which may differ from the edit value due to column formatting or a custom CustomColumnDisplayText event handler.

Examples:

// Get the 'Price' field value from the first visible row
decimal price = (decimal)dataGrid.GetCellValue(0, "Price");

// Set a new value for the 'Status' column in the focused row 
dataGrid.SetCellValue(dataGrid.FocusedRowIndex, "Status", "Approved");

// Get the formatted display text (e.g., "$100.00" instead of 100)
string displayPrice = dataGrid.GetCellDisplayText(0, "Price");

Work with Underlying Data Objects

The DataGrid control includes methods that allow you to retrieve a row's source object (business object) and modify its properties. Use the following members to obtain source items:

Member Description
DataControlBase.FocusedItem Gets the source object for the currently focused row.
GetSourceItem Returns the source object by its index in the data source.
GetSourceItemValue Returns the value of a specific field in the data source at the specified index.
GetSourceItemByRowIndex Returns the source object by a row's index.
GetSourceItemByVisibleRowIndex Returns the source object by a row's visible index.

For an explanation of different row index types, refer to Identify and Get Rows.

Examples

// Example 1: Update the focused item's property
EmployeeInfo emp = dataGrid.FocusedItem as EmployeeInfo;
if (emp != null)
{
    emp.HiredDate = DateTime.Today;
}

// Example 2: Retrieve and modify an item by a row's visible index
var item = dataGrid.GetSourceItemByVisibleRowIndex(2) as Product;
if (item != null)
{
    item.UnitsInStock--;
}

Cell In-place Editors

Cell in-place editors serve two purposes:

cells-editors

The DataGrid uses EMX editors to present and edit values of common data types, by default. For instance, double values are presented using the SpinEditor in-place editor, Boolean values are presented using the CheckEditor control, etc.

You can explicitly assign editors to columns/cells using these approaches:

  1. Specify EMX editors using the GridColumn.EditorProperties property.
  2. Specify EMX editors using the GridColumn.CellTemplate property.
  3. Specify custom editors using the GridColumn.CellTemplate property.

The first approach (GridColumn.EditorProperties) s preferred, as it provides the following advantages:

  • In-place EMX editors and the DataGrid share the same paint theme, ensuring synchronized appearance settings.
  • The DataGrid can correctly obtain display text from cells and export it to various formats (XLSX, PDF, images, and so on). When you use cell templates, cells are exported blank.
  • High performance during initialization, display, and scrolling. The control mimics the editor's appearance in display mode; the actual editor is created only when editing begins and destroyed once editing ends.

To specify an in-place EMX editor using the GridColumn.EditorProperties property, do the following:

  1. Set the GridColumn.EditorProperties property to one of the following BaseEditorProperties class descendants that corresponds to the required editor type:

    • ButtonEditorProperties — Corresponds to and contains settings specific to the ButtonEditor control.
    • CheckEditorProperties — Corresponds to and contains settings specific to the CheckEditor control.
    • ComboBoxEditorProperties — Corresponds to and contains settings specific to the ComboBoxEditor control.
    • DateEditorProperties — Corresponds to and contains settings specific to the DateEditor control.
    • HyperlinkEditorProperties — Corresponds to and contains settings specific to the HyperlinkEditor control.
    • MemoEditorProperties — Corresponds to and contains settings specific to the MemoEditor control.
    • PopupColorEditorProperties — Corresponds to and contains settings specific to the PopupColorEditor control.
    • SegmentedEditorProperties — Corresponds to and contains settings specific to the SegmentedEditor control.
    • SpinEditorProperties — Corresponds to and contains settings specific to the SpinEditor control.
    • TextEditorProperties — Corresponds to and contains settings specific to the TextEditor control.
  2. Modify the settings of the specified BaseEditorProperties descendant object.

Example - Assign a ComboBoxEditor Control to a Column

The following example assigns a ComboBoxEditor editor to a column by setting the GridColumn.EditorProperties property to a ComboBoxEditorProperties object. The ComboBoxEditorProperties.ItemsSource property specifies the source of items to display in the combobox editor's dropdown.

cells-editors-comboboxexample

<mxdg:GridColumn FieldName="Position" Width="*" MinWidth="150">
    <mxdg:GridColumn.EditorProperties>
        <mxe:ComboBoxEditorProperties ItemsSource="{Binding Source={x:Static data:EmployeesData.Positions}}" IsTextEditable="False"/>
    </mxdg:GridColumn.EditorProperties>
</mxdg:GridColumn>

See the following topic for more information: Data Editing.