DataGrid Escalation PathPrimary APIs:
ItemsControl, ListBox, TreeView, Carousel, TabControlVirtualizingPanel, VirtualizingStackPanelContentPresenter, ItemsPresenter, DataTemplate, FuncDataTemplateScrollViewerReference docs:
20-itemscontrol-virtualization-and-recycling.md38-data-templates-and-idatatemplate-selector-patterns.md57-scrollviewer-offset-anchoring-and-snap-points.md52-controls-reference-catalog.md| Modern web UI pattern | Avalonia pattern |
|---|---|
| card masonry/grid dashboard | ItemsControl + custom items panel (UniformGrid, WrapPanel, custom panel) |
| feed/timeline | ListBox/ItemsControl + ScrollViewer + virtualization |
| tree explorer | TreeView + TreeDataTemplate |
| tabbed workspace | TabControl |
| carousel/hero rotator | Carousel / TransitioningContentControl |
HTML/CSS intent: responsive cards with reusable component styles.
Avalonia recipe:
<ItemsControl ItemsSource="{CompiledBinding Cards}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ItemWidth="320" ItemHeight="180" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:CardViewModel">
<Border Classes="dashboard-card" Padding="14" Margin="6">
<StackPanel Spacing="6">
<TextBlock Text="{CompiledBinding Title}" Classes="card-title" />
<TextBlock Text="{CompiledBinding Value}" Classes="card-value" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Use ListBox with virtualization-friendly item templates and avoid heavy nested visual trees.
<ListBox ItemsSource="{CompiledBinding Events}"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:EventItemViewModel">
<Grid ColumnDefinitions="Auto,*" Margin="8">
<Border Width="10" Height="10" CornerRadius="5" Background="{CompiledBinding DotBrush}" />
<StackPanel Grid.Column="1" Margin="10,0,0,0">
<TextBlock Text="{CompiledBinding Title}" />
<TextBlock Text="{CompiledBinding TimestampText}" Classes="muted" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TreeView ItemsSource="{CompiledBinding Nodes}">
<TreeView.ItemTemplate>
<TreeDataTemplate x:DataType="vm:NodeViewModel" ItemsSource="{CompiledBinding Children}">
<TextBlock Text="{CompiledBinding Name}" />
</TreeDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
HTML/CSS:
<table class="orders">
<thead>
<tr><th>ID</th><th>Status</th><th>Total</th></tr>
</thead>
<tbody>
<tr><td>#1042</td><td>Paid</td><td>$128.00</td></tr>
</tbody>
</table>
.orders { width: 100%; border-collapse: collapse; }
.orders th, .orders td { padding: 10px 12px; border-bottom: 1px solid #2a3348; }
.orders th { text-align: left; font-weight: 600; }
Avalonia (table-like layout with ItemsControl):
<StackPanel>
<Grid ColumnDefinitions="120,160,*" Classes="orders-header">
<TextBlock Grid.Column="0" Text="ID" />
<TextBlock Grid.Column="1" Text="Status" />
<TextBlock Grid.Column="2" Text="Total" />
</Grid>
<ItemsControl ItemsSource="{CompiledBinding Orders}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:OrderRowViewModel">
<Grid ColumnDefinitions="120,160,*" Classes="orders-row">
<TextBlock Grid.Column="0" Text="{CompiledBinding Id}" />
<TextBlock Grid.Column="1" Text="{CompiledBinding Status}" />
<TextBlock Grid.Column="2" Text="{CompiledBinding TotalText}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
When column widths should stay aligned between header and every row (similar to HTML table column sizing), use Grid.IsSharedSizeScope + SharedSizeGroup.
<Grid Grid.IsSharedSizeScope="True" RowDefinitions="Auto,*">
<Grid Grid.Row="0" Classes="orders-header">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="ColId" />
<ColumnDefinition SharedSizeGroup="ColStatus" />
<ColumnDefinition SharedSizeGroup="ColTotal" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="ID" />
<TextBlock Grid.Column="1" Text="Status" />
<TextBlock Grid.Column="2" Text="Total" />
</Grid>
<ItemsControl Grid.Row="1" ItemsSource="{CompiledBinding Orders}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:OrderRowViewModel">
<Grid Classes="orders-row">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="ColId" />
<ColumnDefinition SharedSizeGroup="ColStatus" />
<ColumnDefinition SharedSizeGroup="ColTotal" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{CompiledBinding Id}" />
<TextBlock Grid.Column="1" Text="{CompiledBinding Status}" />
<TextBlock Grid.Column="2" Text="{CompiledBinding TotalText}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
DataGrid Escalation PathIf the web table requires built-in sorting, column resize/reorder, selection, and editing semantics, move from handcrafted Grid rows to DataGrid (package-based).
Use Grid + ItemsControl when:
Use DataGrid when:
<!-- Requires Avalonia.Controls.DataGrid package -->
<DataGrid ItemsSource="{CompiledBinding Orders}"
AutoGenerateColumns="False"
CanUserSortColumns="True"
CanUserResizeColumns="True"
GridLinesVisibility="Horizontal">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Id}" Width="SizeToHeader" />
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="*" />
<DataGridTextColumn Header="Total" Binding="{Binding TotalText}" Width="*" />
</DataGrid.Columns>
</DataGrid>
Web inline-edit idiom maps to templated list item states:
TextBox + commit/cancel commands,using Avalonia.Controls;
using Avalonia.Controls.Templates;
var table = new StackPanel();
var header = new Grid
{
ColumnDefinitions = ColumnDefinitions.Parse("120,160,*"),
};
var idHeader = new TextBlock { Text = "ID" };
var statusHeader = new TextBlock { Text = "Status" };
var totalHeader = new TextBlock { Text = "Total" };
Grid.SetColumn(statusHeader, 1);
Grid.SetColumn(totalHeader, 2);
header.Children.Add(idHeader);
header.Children.Add(statusHeader);
header.Children.Add(totalHeader);
table.Children.Add(header);
var rows = new ItemsControl
{
ItemTemplate = new FuncDataTemplate<OrderRowViewModel>((item, _) =>
{
var row = new Grid { ColumnDefinitions = ColumnDefinitions.Parse("120,160,*") };
row.Children.Add(new TextBlock { Text = item.Id });
row.Children.Add(new TextBlock { Text = item.Status });
row.Children.Add(new TextBlock { Text = item.TotalText });
Grid.SetColumn(row.Children[1], 1);
Grid.SetColumn(row.Children[2], 2);
return row;
})
};
table.Children.Add(rows);
// Optional package-based grid when spreadsheet-like interaction is required.
var dataGrid = new DataGrid
{
AutoGenerateColumns = false,
CanUserSortColumns = true,
CanUserResizeColumns = true,
GridLinesVisibility = DataGridGridLinesVisibility.Horizontal
};
dataGrid.Columns.Add(new DataGridTextColumn { Header = "ID", Binding = new Avalonia.Data.Binding("Id") });
dataGrid.Columns.Add(new DataGridTextColumn { Header = "Status", Binding = new Avalonia.Data.Binding("Status") });
dataGrid.Columns.Add(new DataGridTextColumn { Header = "Total", Binding = new Avalonia.Data.Binding("TotalText") });
x:DataType) and simple.DataType alignment with actual item model types.Grid.IsSharedSizeScope and shared column groups.