diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs index 7cb9e7b..11e88c5 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs @@ -639,9 +639,8 @@ private Rect EstimateViewport(Size availableSize) { if (!c.Bounds.Equals(default) && c.TransformToVisual(this) is Matrix transform) { - return new Rect(0, 0, c.Bounds.Width, c.Bounds.Height) - .TransformToAABB(transform) - .Intersect(new(0, 0, double.PositiveInfinity, double.PositiveInfinity)); + var r = new Rect(0, 0, c.Bounds.Width, c.Bounds.Height).TransformToAABB(transform); + return Intersect(r, new(0, 0, double.PositiveInfinity, double.PositiveInfinity)); } c = c?.GetVisualParent(); diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRowsPresenter.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRowsPresenter.cs index fb37172..e946bc0 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRowsPresenter.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRowsPresenter.cs @@ -57,6 +57,17 @@ protected override void UnrealizeElementOnItemRemoved(Control element) ChildIndexChanged?.Invoke(this, new ChildIndexChangedEventArgs(element, ((TreeDataGridRow)element).RowIndex)); } + protected override Size MeasureOverride(Size availableSize) + { + var result = base.MeasureOverride(availableSize); + + // If we have no rows, then get the width from the columns. + if (Columns is not null && (Items is null || Items.Count == 0)) + result = result.WithWidth(Columns.GetEstimatedWidth(availableSize.Width)); + + return result; + } + protected override Size ArrangeOverride(Size finalSize) { Columns?.CommitActualWidths(); diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/TestTemplates.cs b/tests/Avalonia.Controls.TreeDataGrid.Tests/TestTemplates.cs index ab8d7be..c01d8cc 100644 --- a/tests/Avalonia.Controls.TreeDataGrid.Tests/TestTemplates.cs +++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/TestTemplates.cs @@ -61,12 +61,20 @@ public static IControlTemplate TreeDataGridTemplate() { Children = { - new TreeDataGridColumnHeadersPresenter + new ScrollViewer { - Name = "PART_ColumnHeadersPresenter", + Name = "PART_HeaderScrollViewer", + Template = ScrollViewerTemplate(), + Height = 0, + HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden, + VerticalScrollBarVisibility = ScrollBarVisibility.Disabled, [DockPanel.DockProperty] = Dock.Top, - [!TreeDataGridColumnHeadersPresenter.ElementFactoryProperty] = x[!TreeDataGrid.ElementFactoryProperty], - [!TreeDataGridColumnHeadersPresenter.ItemsProperty] = x[!TreeDataGrid.ColumnsProperty], + Content = new TreeDataGridColumnHeadersPresenter + { + Name = "PART_ColumnHeadersPresenter", + [!TreeDataGridColumnHeadersPresenter.ElementFactoryProperty] = x[!TreeDataGrid.ElementFactoryProperty], + [!TreeDataGridColumnHeadersPresenter.ItemsProperty] = x[!TreeDataGrid.ColumnsProperty], + }.RegisterInNameScope(ns), }.RegisterInNameScope(ns), new ScrollViewer { diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs b/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs index 4f7cbd6..5afa60f 100644 --- a/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs +++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs @@ -560,6 +560,69 @@ public void Can_Remove_Selected_Item_Sorted() } } + [AvaloniaFact(Timeout = 10000)] + public void Should_Show_Horizontal_ScrollBar() + { + var (target, items) = CreateTarget(columns: + [ + new TextColumn("ID", x => x.Id, width: new GridLength(100, GridUnitType.Pixel)), + new TextColumn("Title1", x => x.Title, width: new GridLength(100, GridUnitType.Pixel)), + ]); + var scroll = Assert.IsType(target.Scroll); + var headerScroll = Assert.IsType( + target.GetVisualDescendants().Single(x => x.Name == "PART_HeaderScrollViewer")); + + Assert.Equal(new(100, 100), scroll.Viewport); + Assert.Equal(new(200, 1000), scroll.Extent); + Assert.Equal(new(100, 0), headerScroll.Viewport); + Assert.Equal(new(200, 0), headerScroll.Extent); + } + + [AvaloniaFact(Timeout = 10000)] + public void Should_Show_Horizontal_ScrollBar_With_No_Initial_Rows() + { + var (target, items) = CreateTarget(columns: + [ + new TextColumn("ID", x => x.Id, width: new GridLength(100, GridUnitType.Pixel)), + new TextColumn("Title1", x => x.Title, width: new GridLength(100, GridUnitType.Pixel)), + ], itemCount: 0); + var scroll = Assert.IsType(target.Scroll); + var headerScroll = Assert.IsType( + target.GetVisualDescendants().Single(x => x.Name == "PART_HeaderScrollViewer")); + + Assert.Equal(new(100, 100), scroll.Viewport); + Assert.Equal(new(200, 100), scroll.Extent); + Assert.Equal(new(100, 0), headerScroll.Viewport); + Assert.Equal(new(200, 0), headerScroll.Extent); + } + + [AvaloniaFact(Timeout = 10000)] + public void Should_Preserve_Horizontal_ScrollBar_When_Rows_Removed() + { + var (target, items) = CreateTarget(columns: + [ + new TextColumn("ID", x => x.Id, width: new GridLength(100, GridUnitType.Pixel)), + new TextColumn("Title1", x => x.Title, width: new GridLength(100, GridUnitType.Pixel)), + ]); + var scroll = Assert.IsType(target.Scroll); + var headerScroll = Assert.IsType( + target.GetVisualDescendants().Single(x => x.Name == "PART_HeaderScrollViewer")); + + scroll.PropertyChanged += (s, e) => + { + if (e.Property == ScrollViewer.ExtentProperty) + { + } + }; + items.Clear(); + target.UpdateLayout(); + + Assert.Equal(new(100, 100), scroll.Viewport); + Assert.Equal(new(200, 100), scroll.Extent); + Assert.Equal(new(100, 0), headerScroll.Viewport); + Assert.Equal(new(200, 0), headerScroll.Extent); + } + private static void AssertRowIndexes(TreeDataGrid target, int firstRowIndex, int rowCount) { var presenter = target.RowsPresenter;