Use TreeDataGridElementFactory when you need to control which visual controls are created for rows, cells, and headers, and how those controls are recycled.
Customize the factory when you need one of these:
ICell or IRow implementationsFor standard scenarios, keep the default factory.
The grid and presenters call the factory through these stages:
GetDataRecycleKey)CreateElement)RecycleElement)Built-in model to control mapping in the default implementation:
using System;
using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Primitives;
public sealed class MyTreeDataGridElementFactory : TreeDataGridElementFactory
{
protected override Control CreateElement(object? data)
{
return data switch
{
// Keep existing defaults where possible.
CheckBoxCell => new TreeDataGridCheckBoxCell(),
TemplateCell => new TreeDataGridTemplateCell(),
IExpanderCell => new TreeDataGridExpanderCell(),
ICell => new TreeDataGridTextCell(),
IColumn => new TreeDataGridColumnHeader(),
IRow => new TreeDataGridRow(),
_ => throw new NotSupportedException($"Unsupported model type: {data?.GetType().FullName}")
};
}
protected override string GetDataRecycleKey(object? data)
{
// Pool by control category, not by model type instance.
return data switch
{
CheckBoxCell => nameof(TreeDataGridCheckBoxCell),
TemplateCell => nameof(TreeDataGridTemplateCell),
IExpanderCell => nameof(TreeDataGridExpanderCell),
ICell => nameof(TreeDataGridTextCell),
IColumn => nameof(TreeDataGridColumnHeader),
IRow => nameof(TreeDataGridRow),
_ => base.GetDataRecycleKey(data),
};
}
}
Apply it:
grid.ElementFactory = new MyTreeDataGridElementFactory();
Use stable recycle keys. If keys are too specific, reuse drops and allocations rise. If keys are too broad, incompatible controls can be reused incorrectly.
Recommended approach:
CreateElement and key methods symmetricalNotSupportedException during scrolling
Cause: custom model type is returned by source but factory mapping was not updated.
stale visuals after reuse Cause: custom control keeps state that is not reset during realize/unrealize cycle.
heavy memory churn Cause: recycle key prevents effective pooling.
Feature behavior differs from expectations
Cause: one or more options in this scenario are configured differently (source type, column options, sort/selection/edit state).
Fix: compare your setup with the snippet in this article and verify runtime values on Source, Columns, and Selection.
Data changes are not visible in UI
Cause: model or collection notifications are missing, or a replaced collection/source is not re-bound.
Fix: ensure INotifyPropertyChanged/INotifyCollectionChanged flow is active and reassign Source after replacing underlying collections.