Skip to content

Implement TableView - #21511

Merged
MrJul merged 33 commits into
AvaloniaUI:masterfrom
MrJul:feature/table-view
Jul 7, 2026
Merged

MrJul merged 33 commits into
AvaloniaUI:masterfrom
MrJul:feature/table-view

Conversation

@MrJul

@MrJul MrJul commented Jun 6, 2026 •

Copy link
Copy Markdown
Member

What does the pull request do?

This PR implements a tabular view for data. It bridges the gap between a simple ListBox and a fully fledged DataGrid/TreeDataGrid, for read-only data. See #21237 for details.

The component is fully unit tested.

Features

  • Read-only data
  • XAML column definitions:
    • Cell content defined using either a binding or a cell template
    • Overridable ControlTheme for header and cells
    • Absolute and star-sized column widths
    • Content horizontal alignment
  • Resizable columns (can be disabled)
  • Cell recycling

API diff

  namespace Avalonia.Controls
  {
+     public class TableView : ListBox
+     {
+         public static readonly StyledProperty<bool> CanUserResizeColumnsProperty;
+         public static readonly DirectProperty<TableView, AvaloniaList<TableViewColumn>?> ColumnsProperty;
+         public TableView();
+         public bool CanUserResizeColumns { get; set; }
+         public AvaloniaList<TableViewColumn>? Columns { get; set; }
+     }
+     public class TableViewCell : ContentControl
+     {
+         public static readonly DirectProperty<TableViewCell, TableViewColumn?> ColumnProperty;
+         public TableViewCell();
+         public TableViewColumn? Column { get; }
+     }
+     public class TableViewColumn : Avalonia.StyledElement
+     {
+         public static readonly DirectProperty<TableViewColumn, double> ActualWidthProperty;
+         public static readonly StyledProperty<BindingBase?> BindingProperty;
+         public static readonly DirectProperty<TableViewColumn, bool> CanUserEffectivelyResizeProperty;
+         public static readonly StyledProperty<bool?> CanUserResizeProperty;
+         public static readonly StyledProperty<IDataTemplate?> CellTemplateProperty;
+         public static readonly StyledProperty<ControlTheme?> CellThemeProperty;
+         public static readonly StyledProperty<object?> HeaderProperty;
+         public static readonly StyledProperty<IDataTemplate?> HeaderTemplateProperty;
+         public static readonly StyledProperty<ControlTheme?> HeaderThemeProperty;
+         public static readonly StyledProperty<HorizontalAlignment> HorizontalContentAlignmentProperty;
+         public static readonly DirectProperty<TableViewColumn, TableView?> TableViewProperty;
+         public static readonly StyledProperty<GridLength> WidthProperty;
+         public TableViewColumn();
+         public double ActualWidth { get; }
+         public BindingBase? Binding { get; set; }
+         public bool CanUserEffectivelyResize { get; }
+         public bool? CanUserResize { get; set; }
+         public IDataTemplate? CellTemplate { get; set; }
+         public ControlTheme? CellTheme { get; set; }
+         public object? Header { get; set; }
+         public IDataTemplate? HeaderTemplate { get; set; }
+         public ControlTheme? HeaderTheme { get; set; }
+         public HorizontalAlignment HorizontalContentAlignment { get; set; }
+         public TableView? TableView { get; }
+         public GridLength Width { get; set; }
+     }
+     public class TableViewColumnHeader : ContentControl
+     {
+         public static readonly DirectProperty<TableViewColumnHeader, TableViewColumn?> ColumnProperty;
+         public TableViewColumnHeader();
+         public TableViewColumn? Column { get; }
+     }
+     public class TableViewRow : ListBoxItem
+     {
+         public TableViewRow();
+     }
  }
  namespace Avalonia.Controls.Presenters
  {
+     public class TableViewColumnHeadersPresenter : Panel
+     {
+         public TableViewColumnHeadersPresenter();
+     }
+     public class TableViewCellsPresenter : Panel
+     {
+         public TableViewCellsPresenter();
+     }
  }

(protected override members are excluded for brevity)

Fixed issues

@MrJul MrJul added feature api-needs-review The PR adds new public APIs that should be reviewed. labels Jun 6, 2026
@MrJul MrJul changed the title Feature/table view Implement TableView Jun 6, 2026
@MrJul MrJul added this to the 12.1 milestone Jun 6, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0066113-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Comment on lines +24 to +28
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}"
Padding="{DynamicResource TableViewRowPadding}"
DockPanel.Dock="Top">
<TableViewColumnHeadersPresenter />
</Border>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't TableViewColumnHeadersPresenter draw its own background and set padding? Background then can be defined on TableViewColumnHeadersPresenter theme directy.
Both changes should make re-styling easier.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to implement Padding specifically on that panel, which would be a bit unexpected. Users still won't be able to customize things such as BorderBrush, BorderThickness, etc., unless we add them all to the TableViewColumnHeadersPresenter.

We can either:

  • Keep it as is, the template isn't that hard to change (I can add a Name to the Border so it's easier to refer in styles).
  • Add a new templated control dedicated to that purpose, e.g. TableViewColumnHeadersRow containing the presenter. This solution expands the public API, but is similar to the Row/Presenter types we already have for normal rows.

@maxkatz6

maxkatz6 commented Jun 7, 2026 •

Copy link
Copy Markdown
Member

After recent surprises with logical/visual tree inconsistences in other controls, can we check how it is for this control?

Visual tree should be natural, as it is defined by templates.
And logical tree can be something like this:

TableView
   TableViewColumnHeadersPresenter 
       TableViewColumnHeader
       TableViewColumnHeader
   TableViewRow
     TableViewCell
     TableViewCell
   TableViewRow
     TableViewCell
     TableViewCell
   TableViewRow
     TableViewCell
     TableViewCell

Note, ":nth-child" handling is an extra complication here - we might end up adding RowsPresenter for consistency.

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067143-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

maxkatz6
maxkatz6 previously approved these changes Jul 6, 2026
@maxkatz6

maxkatz6 commented Jul 6, 2026 •

Copy link
Copy Markdown
Member

One nit, we should prevent developers from using SelectingItemsControl properties that are no-op on TableView.
Like DisplayMemberBinding or SelectedValueBinding.
Something like this might be enough, defined in TableView, overriding base class definition:

[Obsolete]
public new BindingBase? DisplayMemberBinding {get;set;}

@kekekeks kekekeks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked only the api

Comment thread src/Avalonia.Controls/TableView.cs Resolved
Comment thread src/Avalonia.Controls/TableView.cs Resolved
Comment thread src/Avalonia.Controls/TableView.cs Resolved
Comment thread src/Avalonia.Controls/TableViewCell.cs Resolved

@kekekeks kekekeks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maxkatz6
maxkatz6 previously approved these changes Jul 6, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067197-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul
MrJul enabled auto-merge July 7, 2026 06:42
@MrJul
MrJul dismissed kekekeks’s stale review July 7, 2026 07:36

Review addressed.

@MrJul
MrJul added this pull request to the merge queue Jul 7, 2026
Merged via the queue into AvaloniaUI:master with commit a0e17b6 Jul 7, 2026
11 checks passed
@MrJul
MrJul deleted the feature/table-view branch July 7, 2026 08:12
@MrJul MrJul added api-approved The new public APIs have been approved. and removed api-needs-review The PR adds new public APIs that should be reviewed. labels Jul 8, 2026
@Bobsoftru

Copy link
Copy Markdown

What am I missing in TableView . 1. Smooth movement when pressing the arrow from down to up. 2. Missing tags in TableViewColumn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-approved The new public APIs have been approved. feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement a simple TableView

6 participants