A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

832 lines
29 KiB

using System;
using System.Collections;
using System.Linq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Controls.UnitTests;
public sealed class TableViewTests : ScopedTestBase
{
[Fact]
public void Container_For_Each_Item_Is_TableViewRow()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo", "Bar", "Baz" });
Prepare(target);
var containers = target.GetRealizedContainers().ToList();
Assert.Equal(3, containers.Count);
Assert.All(containers, c => Assert.IsType<TableViewRow>(c));
}
[Fact]
public void Row_Has_One_Cell_Per_Column()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn());
target.Columns.Add(new TableViewColumn());
target.Columns.Add(new TableViewColumn());
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cells = GetCellsPresenter(row).Children;
Assert.Equal(3, cells.Count);
Assert.All(cells, c => Assert.IsType<TableViewCell>(c));
// Cells must also be part of the row's logical tree.
var logicalChildren = row.GetLogicalChildren().ToArray();
Assert.Equal(cells, logicalChildren);
}
[Fact]
public void Column_TableView_Is_Set_When_Added_And_Unset_When_Removed()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
var column = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
target.Columns.Add(column);
Prepare(target);
Assert.Same(target, column.TableView);
target.Columns.Remove(column);
Assert.Null(column.TableView);
}
[Fact]
public void Column_LogicalParent_Is_Set_When_Added_And_Unset_When_Removed()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
var column = new TableViewColumn();
target.Columns.Add(column);
Prepare(target);
Assert.Same(target, column.GetLogicalParent());
target.Columns.Remove(column);
Assert.Null(column.GetLogicalParent());
}
[Fact]
public void Column_Receives_Styles_From_TableView()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
var style = new Style(x => x.OfType<TableViewColumn>().Class("right-align"))
{
Setters = { new Setter(TableViewColumn.HorizontalContentAlignmentProperty, HorizontalAlignment.Right) }
};
target.Styles.Add(style);
var column = new TableViewColumn
{
Classes = { "right-align" }
};
target.Columns.Add(column);
Prepare(target);
Assert.Equal(HorizontalAlignment.Right, column.HorizontalContentAlignment);
}
[Fact]
public void Column_Cannot_Belong_To_Two_TableViews()
{
using var app = Start();
var column = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
var first = CreateTarget(new[] { "Foo" });
first.Columns.Add(column);
Prepare(first);
Assert.Same(first, column.TableView);
var second = CreateTarget(new[] { "Bar" });
second.Columns.Add(column);
Assert.Throws<InvalidOperationException>(() => Prepare(second));
}
[Fact]
public void Adding_Column_Adds_Cell_To_Realized_Rows_And_Headers()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cellsPresenter = GetCellsPresenter(row);
Assert.Equal(2, cellsPresenter.Children.Count);
var headersPresenter = GetColumnHeadersPresenter(target);
Assert.Equal(2, headersPresenter.Children.Count);
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Assert.Equal(3, cellsPresenter.Children.Count);
Assert.Equal(3, headersPresenter.Children.Count);
// The newly added cell must also be part of the row's logical tree.
var logicalChildren = row.GetLogicalChildren().ToArray();
Assert.Equal(cellsPresenter.Children, logicalChildren);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
public void Adding_Hidden_Column_Updates_Cells_And_Headers(int columnIndex)
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Styles.Add(new Style(x => x.OfType<TableViewColumn>().Class("hidden"))
{
Setters = { new Setter(TableViewColumn.IsVisibleProperty, false) },
});
target.Columns.Add(new TableViewColumn());
Prepare(target);
var column = new TableViewColumn { Classes = { "hidden" } };
target.Columns.Insert(columnIndex, column);
Layout(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
Assert.False(GetCellsPresenter(row).Children[columnIndex].IsVisible);
Assert.False(GetColumnHeadersPresenter(target).Children[columnIndex].IsVisible);
Assert.True(GetCellsPresenter(row).Children[1 - columnIndex].IsVisible);
Assert.True(GetColumnHeadersPresenter(target).Children[1 - columnIndex].IsVisible);
}
[Fact]
public void Removing_Column_Removes_Cell_From_Realized_Rows_And_Headers()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cellsPresenter = GetCellsPresenter(row);
Assert.Equal(3, cellsPresenter.Children.Count);
var headersPresenter = GetColumnHeadersPresenter(target);
Assert.Equal(3, headersPresenter.Children.Count);
var removedCell = (TableViewCell)cellsPresenter.Children[2];
target.Columns.RemoveAt(2);
Assert.Equal(2, cellsPresenter.Children.Count);
Assert.Equal(2, headersPresenter.Children.Count);
// The removed cell must also be detached from the row's logical tree, while the remaining cells stay in it.
var logicalChildren = row.GetLogicalChildren().ToArray();
Assert.DoesNotContain(removedCell, logicalChildren);
Assert.Equal(cellsPresenter.Children, logicalChildren);
}
[Fact]
public void Changing_Column_Width_Does_Not_Recreate_Cells()
{
using var app = Start();
var column = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(column);
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target, width: 200);
var presenter = GetCellsPresenter((TableViewRow)target.GetRealizedContainers().Single());
var cellsBefore = presenter.Children.ToArray();
column.Width = new GridLength(2, GridUnitType.Star);
Layout(target);
var cellsAfter = presenter.Children.ToArray();
Assert.Equal(cellsBefore, cellsAfter);
}
[Fact]
public void Changing_Column_Width_Invalidates_Row_Presenter_Measure()
{
using var app = Start();
var column = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(column);
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target, width: 200);
var presenter = GetCellsPresenter((TableViewRow)target.GetRealizedContainers().Single());
Assert.True(presenter.IsMeasureValid);
column.Width = new GridLength(2, GridUnitType.Star);
Assert.False(presenter.IsMeasureValid);
}
[Fact]
public void Changing_Column_Width_Updates_ActualWidth_After_Layout()
{
using var app = Start();
var column = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(column);
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target, width: 200);
Assert.Equal(100, target.Columns[0].ActualWidth);
Assert.Equal(100, target.Columns[1].ActualWidth);
column.Width = new GridLength(3, GridUnitType.Star);
Layout(target);
Assert.Equal(150, target.Columns[0].ActualWidth);
Assert.Equal(50, target.Columns[1].ActualWidth);
}
[Fact]
public void Hiding_Column_Closes_Gap_Without_Recreating_Controls()
{
using var app = Start();
var column = new TableViewColumn { Width = new GridLength(80) };
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(column);
target.Columns.Add(new TableViewColumn());
Prepare(target, width: 200);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cells = GetCellsPresenter(row);
var headers = GetColumnHeadersPresenter(target);
var originalCells = cells.Children.ToArray();
var originalHeaders = headers.Children.ToArray();
column.IsVisible = false;
Layout(target);
Assert.False(cells.Children[0].IsVisible);
Assert.False(headers.Children[0].IsVisible);
Assert.Equal(0, cells.Children[1].Bounds.X);
Assert.Equal(0, headers.Children[1].Bounds.X);
Assert.Equal(200, target.Columns[1].ActualWidth);
Assert.Equal(0, column.ActualWidth);
Assert.Equal(new GridLength(80), column.Width);
column.IsVisible = true;
Layout(target);
Assert.True(cells.Children[0].IsVisible);
Assert.True(headers.Children[0].IsVisible);
Assert.Equal(80, cells.Children[1].Bounds.X);
Assert.Equal(80, headers.Children[1].Bounds.X);
Assert.Equal(originalCells, cells.Children);
Assert.Equal(originalHeaders, headers.Children);
}
[Fact]
public void Hidden_Columns_Do_Not_Contribute_To_Row_Size()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
var column = new TableViewColumn { IsVisible = false };
target.Columns.Add(column);
target.Columns.Add(new TableViewColumn());
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cells = GetCellsPresenter(row);
cells.Children[0].Height = 80;
cells.Children[1].Height = 20;
Layout(target);
Assert.False(cells.Children[0].IsVisible);
Assert.False(GetColumnHeadersPresenter(target).Children[0].IsVisible);
Assert.Equal(20, cells.DesiredSize.Height);
column.IsVisible = true;
Layout(target);
Assert.Equal(80, cells.DesiredSize.Height);
column.IsVisible = false;
target.Columns[1].IsVisible = false;
Layout(target);
Assert.Equal(default, cells.DesiredSize);
column.IsVisible = true;
Layout(target);
Assert.Equal(80, cells.DesiredSize.Height);
}
[Fact]
public void Replacing_Columns_Collection_Updates_Realized_Rows_And_Headers()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cellsPresenter = GetCellsPresenter(row);
Assert.Equal(2, cellsPresenter.Children.Count);
var headersPresenter = GetColumnHeadersPresenter(target);
Assert.Equal(2, headersPresenter.Children.Count);
var oldCells = cellsPresenter.Children.ToArray();
target.Columns =
[
new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) },
new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) },
new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) }
];
Assert.Equal(3, cellsPresenter.Children.Count);
Assert.Equal(3, headersPresenter.Children.Count);
// The new cells must be in the row's logical tree, and the old ones gone.
var logicalChildren = row.GetLogicalChildren().ToArray();
Assert.Equal(cellsPresenter.Children, logicalChildren);
Assert.All(oldCells, cell => Assert.DoesNotContain(cell, logicalChildren));
}
[Fact]
public void Cell_Content_Defaults_To_Row_Item_When_No_Template_Or_Binding()
{
using var app = Start();
var item = new Person("Alice");
var target = CreateTarget(new[] { item });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var firstCell = (TableViewCell)GetCellsPresenter(row).Children[0];
Assert.Same(item, firstCell.Content);
}
[Fact]
public void Cell_Uses_Column_Binding()
{
using var app = Start();
var target = CreateTarget(new[] { new Person("Alice"), new Person("Bob") });
target.Columns.Add(new TableViewColumn
{
Width = new GridLength(1, GridUnitType.Star),
Binding = new ReflectionBinding(nameof(Person.Name))
});
target.Columns.Add(new TableViewColumn
{
Width = new GridLength(1, GridUnitType.Star)
});
Prepare(target);
var rows = target.GetRealizedContainers().Cast<TableViewRow>().ToArray();
var firstCell = (TableViewCell)GetCellsPresenter(rows[0]).Children[0];
var secondCell = (TableViewCell)GetCellsPresenter(rows[1]).Children[0];
Assert.Equal("Alice", firstCell.Content);
Assert.Equal("Bob", secondCell.Content);
}
[Fact]
public void Hidden_Column_Preserves_Width_And_Visibility_Bindings()
{
using var app = Start();
var model = new Border { IsVisible = false, Tag = new GridLength(80) };
var target = CreateTarget(new[] { "Foo" });
target.DataContext = model;
var column = new TableViewColumn();
column.Bind(TableViewColumn.WidthProperty, new ReflectionBinding(nameof(Border.Tag)));
column.Bind(TableViewColumn.IsVisibleProperty, new ReflectionBinding(nameof(Border.IsVisible)));
target.Columns.Add(column);
target.Columns.Add(new TableViewColumn());
Prepare(target, width: 200);
Assert.False(column.IsVisible);
Assert.Equal(200, target.Columns[1].ActualWidth);
model.Tag = new GridLength(120);
model.IsVisible = true;
Layout(target);
Assert.True(column.IsVisible);
Assert.Equal(120, column.ActualWidth);
Assert.Equal(80, target.Columns[1].ActualWidth);
model.IsVisible = false;
Layout(target);
Assert.False(column.IsVisible);
Assert.Equal(200, target.Columns[1].ActualWidth);
}
[Fact]
public void Cell_Uses_Column_CellTemplate()
{
using var app = Start();
var template = new FuncDataTemplate<object>((_, _) => new TextBlock());
var item = new Person("Alice");
var target = CreateTarget(new[] { item });
target.Columns.Add(new TableViewColumn
{
Width = new GridLength(1, GridUnitType.Star),
CellTemplate = template
});
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var firstCell = (TableViewCell)GetCellsPresenter(row).Children[0];
Assert.Same(template, firstCell.ContentTemplate);
Assert.Same(item, firstCell.Content);
}
[Fact]
public void Cell_Uses_Column_CellTheme()
{
using var app = Start();
var cellTheme = new ControlTheme(typeof(TableViewCell));
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn
{
Width = new GridLength(1, GridUnitType.Star),
CellTheme = cellTheme
});
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var firstCell = (TableViewCell)GetCellsPresenter(row).Children[0];
var secondCell = (TableViewCell)GetCellsPresenter(row).Children[1];
Assert.Same(cellTheme, firstCell.Theme);
Assert.Null(secondCell.Theme);
}
[Fact]
public void Cell_Column_Property_Is_Set_To_Owning_Column()
{
using var app = Start();
var column0 = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
var column1 = new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) };
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(column0);
target.Columns.Add(column1);
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var firstCell = (TableViewCell)GetCellsPresenter(row).Children[0];
var secondCell = (TableViewCell)GetCellsPresenter(row).Children[1];
Assert.Same(column0, firstCell.Column);
Assert.Same(column1, secondCell.Column);
}
[Fact]
public void Cell_Uses_Column_HorizontalContentAlignment()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn
{
Width = new GridLength(1, GridUnitType.Star),
HorizontalContentAlignment = HorizontalAlignment.Right
});
target.Columns.Add(new TableViewColumn { Width = new GridLength(1, GridUnitType.Star) });
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var firstCell = (TableViewCell)GetCellsPresenter(row).Children[0];
var secondCell = (TableViewCell)GetCellsPresenter(row).Children[1];
Assert.Equal(HorizontalAlignment.Right, firstCell.HorizontalContentAlignment);
Assert.Equal(HorizontalAlignment.Left, secondCell.HorizontalContentAlignment);
}
[Fact]
public void Changing_Column_Properties_Updates_Existing_Headers_And_Cells()
{
using var app = Start();
var cellThemeA = new ControlTheme(typeof(TableViewCell));
var cellThemeB = new ControlTheme(typeof(TableViewCell));
var headerThemeA = new ControlTheme(typeof(TableViewColumnHeader));
var headerThemeB = new ControlTheme(typeof(TableViewColumnHeader));
var headerTemplateA = new FuncDataTemplate<object>((_, _) => new TextBlock());
var headerTemplateB = new FuncDataTemplate<object>((_, _) => new TextBlock());
var item = new Person("Alice", "Ally");
var column = new TableViewColumn
{
Width = new GridLength(1, GridUnitType.Star),
CellTheme = cellThemeA,
HorizontalContentAlignment = HorizontalAlignment.Left,
Binding = new ReflectionBinding(nameof(Person.Name)),
Header = "H1",
HeaderTheme = headerThemeA,
HeaderTemplate = headerTemplateA
};
var target = CreateTarget(new[] { item });
target.Columns.Add(column);
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var cell = (TableViewCell)GetCellsPresenter(row).Children[0];
var header = (TableViewColumnHeader)GetColumnHeadersPresenter(target).Children[0];
Assert.Same(cellThemeA, cell.Theme);
Assert.Equal(HorizontalAlignment.Left, cell.HorizontalContentAlignment);
Assert.Null(cell.ContentTemplate);
Assert.Equal("Alice", cell.Content);
Assert.Same(headerThemeA, header.Theme);
Assert.Equal(HorizontalAlignment.Left, header.HorizontalContentAlignment);
Assert.Same(headerTemplateA, header.ContentTemplate);
Assert.Equal("H1", header.Content);
// Mutating the column after the cell and header were built should update both.
// Switch the Binding first to confirm it's reflected in the cell content.
column.CellTheme = cellThemeB;
column.HorizontalContentAlignment = HorizontalAlignment.Right;
column.Binding = new ReflectionBinding(nameof(Person.Nickname));
column.Header = "H2";
column.HeaderTheme = headerThemeB;
column.HeaderTemplate = headerTemplateB;
Assert.Same(cellThemeB, cell.Theme);
Assert.Equal(HorizontalAlignment.Right, cell.HorizontalContentAlignment);
Assert.Null(cell.ContentTemplate);
Assert.Equal("Ally", cell.Content);
Assert.Same(headerThemeB, header.Theme);
Assert.Equal(HorizontalAlignment.Right, header.HorizontalContentAlignment);
Assert.Same(headerTemplateB, header.ContentTemplate);
Assert.Equal("H2", header.Content);
// CellTemplate takes priority over Binding: the row item flows through the template.
var cellTemplateB = new FuncDataTemplate<object>((_, _) => new TextBlock());
column.CellTemplate = cellTemplateB;
Assert.Same(cellTemplateB, cell.ContentTemplate);
Assert.Same(item, cell.Content);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void Re_Templating_Row_Detaches_Old_Cells_And_Rebuilds_New_Cells(bool isVisible)
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.Columns.Add(new TableViewColumn { IsVisible = isVisible });
target.Columns.Add(new TableViewColumn());
Prepare(target);
var row = (TableViewRow)target.GetRealizedContainers().Single();
var oldCells = GetCellsPresenter(row).Children.ToArray();
Assert.Equal(2, oldCells.Length);
Assert.Equal(oldCells, row.GetLogicalChildren());
row.Template = RowTemplate();
row.ApplyTemplate();
var newCells = GetCellsPresenter(row).Children.ToArray();
Assert.Equal(2, newCells.Length);
Assert.Equal(isVisible, newCells[0].IsVisible);
Assert.True(newCells[1].IsVisible);
Assert.All(oldCells, cell => Assert.Null(cell.Parent));
Assert.Equal(newCells, row.GetLogicalChildren());
}
[Fact]
public void CanUserResizeColumns_Defaults_To_True()
{
Assert.True(new TableView().CanUserResizeColumns);
}
[Theory]
[InlineData(true, null, true)] // inherits the table's value
[InlineData(true, true, true)] // column opts in
[InlineData(true, false, false)] // column opts out
[InlineData(false, null, false)] // inherits the table's value
[InlineData(false, true, true)] // column opts in
[InlineData(false, false, false)] // column opts out
public void Column_CanUserEffectivelyResize_Combines_TableView_And_Column_Settings(
bool canResizeColumns,
bool? canResize,
bool expected)
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.CanUserResizeColumns = canResizeColumns;
var column = new TableViewColumn { CanUserResize = canResize };
target.Columns.Add(column);
Prepare(target);
Assert.Equal(expected, column.CanUserEffectivelyResize);
}
[Fact]
public void Column_CanUserEffectivelyResize_Updates_When_TableView_CanResizeColumns_Changes()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
var column = new TableViewColumn();
target.Columns.Add(column);
Prepare(target);
Assert.True(column.CanUserEffectivelyResize);
target.CanUserResizeColumns = false;
Assert.False(column.CanUserEffectivelyResize);
target.CanUserResizeColumns = true;
Assert.True(column.CanUserEffectivelyResize);
}
[Fact]
public void Column_CanUserEffectivelyResize_Updates_When_Column_CanResize_Changes()
{
using var app = Start();
var target = CreateTarget(new[] { "Foo" });
target.CanUserResizeColumns = false;
var column = new TableViewColumn();
target.Columns.Add(column);
Prepare(target);
Assert.False(column.CanUserEffectivelyResize);
column.CanUserResize = true;
Assert.True(column.CanUserEffectivelyResize);
column.CanUserResize = null;
Assert.False(column.CanUserEffectivelyResize);
}
private static IDisposable Start()
=> UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
private static TableView CreateTarget(IEnumerable items)
=> new()
{
Template = TableViewTemplate(),
ItemContainerTheme = TableViewRowTheme(),
ItemsSource = items
};
private static TableViewCellsPresenter GetCellsPresenter(TableViewRow row)
{
var presenter = row.GetVisualDescendants()
.OfType<TableViewCellsPresenter>()
.FirstOrDefault();
Assert.NotNull(presenter);
return presenter;
}
private static TableViewColumnHeadersPresenter GetColumnHeadersPresenter(TableView target)
{
var presenter = target.GetVisualDescendants()
.OfType<TableViewColumnHeadersPresenter>()
.FirstOrDefault();
Assert.NotNull(presenter);
return presenter;
}
private static void Prepare(TableView target, double width = 300, double height = 200)
{
target.Width = width;
target.Height = height;
var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass();
}
private static void Layout(Control control)
=> control.GetLayoutManager()?.ExecuteLayoutPass();
private static FuncControlTemplate TableViewTemplate()
=> new FuncControlTemplate<TableView>((parent, scope) =>
new DockPanel
{
Children =
{
new TableViewColumnHeadersPresenter
{
[DockPanel.DockProperty] = Dock.Top
},
new ScrollViewer
{
Name = "PART_ScrollViewer",
Template = ScrollViewerTemplate(),
Content = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
[~ItemsPresenter.ItemsPanelProperty] =
parent.GetObservable(ItemsControl.ItemsPanelProperty).ToBinding()
}.RegisterInNameScope(scope)
}.RegisterInNameScope(scope)
}
});
private static FuncControlTemplate ScrollViewerTemplate()
=> new FuncControlTemplate<ScrollViewer>((_, scope) =>
new Panel
{
Children =
{
new ScrollContentPresenter
{
Name = "PART_ContentPresenter"
}.RegisterInNameScope(scope)
}
});
private static ControlTheme TableViewRowTheme()
=> new(typeof(TableViewRow))
{
Setters =
{
new Setter(TemplatedControl.TemplateProperty, RowTemplate())
}
};
private static FuncControlTemplate<TableViewRow> RowTemplate()
=> new((_, scope) =>
new TableViewCellsPresenter
{
Name = "PART_CellsPresenter"
}.RegisterInNameScope(scope));
private class Person
{
public Person(string name, string? nickname = null)
{
Name = name;
Nickname = nickname;
}
public string Name { get; }
public string? Nickname { get; }
}
}