Skip to content

Implement TableView#21511

Open
MrJul wants to merge 22 commits into
AvaloniaUI:masterfrom
MrJul:feature/table-view
Open

Implement TableView#21511
MrJul wants to merge 22 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> CanResizeColumnsProperty;
+         public static readonly DirectProperty<TableView, AvaloniaList<TableViewColumn>?> ColumnsProperty;
+         public TableView();
+         public bool CanResizeColumns { 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> CanEffectivelyResizeProperty;
+         public static readonly StyledProperty<bool?> CanResizeProperty;
+         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 CanEffectivelyResize { get; }
+         public bool? CanResize { 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 needs-api-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 thread src/Avalonia.Themes.Fluent/Controls/TableViewRow.xaml Outdated
Comment thread src/Avalonia.Themes.Fluent/Controls/TableViewColumnHeader.xaml Outdated
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.

Comment thread src/Avalonia.Controls/Presenters/TableViewRowPresenter.cs Outdated
Comment thread src/Avalonia.Controls/Presenters/TableViewRowPresenter.cs Outdated
@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.

@MrJul

MrJul commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

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

The cells weren't part of the logical tree, I've added them. The tree now looks like this:
image

Note: as you mentioned in the linked issue, having the column headers in the logical tree breaks :nth-child unless we special case them. Plus, I don't think the columns presenter itself should be part of the logical tree (the row presenters aren't). I'd prefer if we have a special row for it, as I suggested in #21511 (comment).

Whatever we do, :nth-child should be fixed first. It's much more important for that selector to work as expected than for headers to be part of the logical tree, imo.

@MrJul MrJul requested a review from maxkatz6 June 8, 2026 10:01
@avaloniaui-bot

Copy link
Copy Markdown

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

@maxkatz6

maxkatz6 commented Jun 8, 2026

Copy link
Copy Markdown
Member

Yeah, current row-only solution is good to me

@Bobsoftru

Copy link
Copy Markdown

It is not clear why a summary line is not made, even without any bells and whistles and even without automatic calculation; it is needed in 70% of cases.

@maxkatz6

Copy link
Copy Markdown
Member

@Bobsoftru what do you mean by summary line? A special row on the bottom with some sort of aggregation per cell? If so, it should be possible to implement one in user code.
Our goal with this control is simple table-visualization, without extra features like pagination or status bars that can be implemented indepdendently from the control.

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

Labels

feature needs-api-review The PR adds new public APIs that should be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement a simple TableView

4 participants