Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions samples/WinUI.TableView.SampleApp/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private void OnNavigationSelectionChanged(NavigationView sender, NavigationViewS
"Data Export" => typeof(ExportPage),
"Large Dataset" => typeof(LargeDataPage),
"Conditional Cell Styling" => typeof(ConditionalStylingPage),
"Column Sizing" => typeof(ColumnSizingPage),
_ => typeof(BlankPage)
};

Expand Down
43 changes: 43 additions & 0 deletions samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<Page x:Class="WinUI.TableView.SampleApp.Pages.ColumnSizingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:WinUI.TableView.SampleApp.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:WinUI.TableView.SampleApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tv="using:WinUI.TableView"
xmlns:ui="using:CommunityToolkit.WinUI"
d:DataContext="{d:DesignInstance Type=local:ExampleViewModel}"
mc:Ignorable="d"
DataContextChanged="OnDataContextChanged">

<Grid>
<controls:SamplePresenter Description="This sample demonstrates the different ways a column can be sized."
Header="Column Sizing">
<controls:SamplePresenter.Example>
<tv:TableView x:Name="tableView"
ItemsSource="{Binding Items}" />
</controls:SamplePresenter.Example>
<controls:SamplePresenter.Options>
<StackPanel Spacing="16"
MinWidth="200">
<ComboBox x:Name="columnAutoWidthMode"
HorizontalAlignment="Stretch"
Header="Column Auto Width Mode"
SelectedItem="{Binding ColumnAutoWidthMode, Mode=TwoWay, ElementName=tableView}"
ItemsSource="{ui:EnumValues Type=tv:TableViewColumnAutoWidthMode}" />
</StackPanel>
</controls:SamplePresenter.Options>
<controls:SamplePresenter.Xaml>
<x:String xml:space="preserve">
&lt;tv:TableView ItemsSource="{Binding Items}"
ColumnAutoWidthMode="$(ColumnAutoWidthMode)"/>
</x:String>
</controls:SamplePresenter.Xaml>
<controls:SamplePresenter.Substitutions>
<controls:CodeSubstitution Key="ColumnAutoWidthMode"
Value="{x:Bind columnAutoWidthMode.SelectedItem, Mode=OneWay}" />
</controls:SamplePresenter.Substitutions>
</controls:SamplePresenter>
</Grid>
</Page>
20 changes: 20 additions & 0 deletions samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace WinUI.TableView.SampleApp.Pages;

public sealed partial class ColumnSizingPage : Page
{
public ColumnSizingPage()
{
InitializeComponent();

}

private void OnDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
if (DataContext is not ExampleViewModel viewModel) return;

viewModel.Items = [.. ExampleViewModel.ItemsList.Take(20)];
}
}
25 changes: 25 additions & 0 deletions src/Columns/TableViewColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ public double ActualWidth
set => SetValue(ActualWidthProperty, value);
}

/// <summary>
/// Gets or sets the ColumnAutoWidthMode of the column.
/// </summary>
public TableViewColumnAutoWidthMode? ColumnAutoWidthMode
{
get => (TableViewColumnAutoWidthMode?)GetValue(ColumnAutoWidthModeProperty);
set => SetValue(ColumnAutoWidthModeProperty, value);
}

/// <summary>
/// Gets or sets a value indicating whether the column can be resized.
/// </summary>
Expand Down Expand Up @@ -508,6 +517,17 @@ private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChan
}
}

/// <summary>
/// Handles changes to the ColumnAutoWidthMode property.
/// </summary>
private static void OnColumnAutoWidthModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TableViewColumn column)
{
column.TableView?.RefreshColumnsAutoWidth([column]);
}
}

/// <summary>
/// Handles changes to the CanFilter property.
/// </summary>
Expand Down Expand Up @@ -579,6 +599,11 @@ public string? SortMemberPath
/// </summary>
public static readonly DependencyProperty ActualWidthProperty = DependencyProperty.Register(nameof(ActualWidth), typeof(double), typeof(TableViewColumn), new PropertyMetadata(0d, OnPropertyChanged));

/// <summary>
/// Identifies the ColumnAutoWidthMode dependency property.
/// </summary>
public static readonly DependencyProperty ColumnAutoWidthModeProperty = DependencyProperty.Register(nameof(ColumnAutoWidthMode), typeof(TableViewColumnAutoWidthMode?), typeof(TableViewColumn), new PropertyMetadata(null, OnColumnAutoWidthModeChanged));

/// <summary>
/// Identifies the CanResize dependency property.
/// </summary>
Expand Down
25 changes: 25 additions & 0 deletions src/TableView.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ public partial class TableView
/// </summary>
public static readonly DependencyProperty RowHeaderTemplateSelectorProperty = DependencyProperty.Register(nameof(RowHeaderTemplateSelector), typeof(DataTemplateSelector), typeof(TableView), new PropertyMetadata(null, OnRowHeaderTemplateChanged));

/// <summary>
/// Identifies the ColumnAutoWidthMode dependency property.
/// </summary>
public static readonly DependencyProperty ColumnAutoWidthModeProperty = DependencyProperty.Register(nameof(ColumnAutoWidthMode), typeof(TableViewColumnAutoWidthMode), typeof(TableView), new PropertyMetadata(TableViewColumnAutoWidthMode.Both, OnColumnAutoWidthModeChanged));

/// <summary>
/// Identifies the FrozenColumnCount dependency property.
/// </summary>
Expand Down Expand Up @@ -792,6 +797,15 @@ public DataTemplateSelector? RowHeaderTemplateSelector
set => SetValue(RowHeaderTemplateSelectorProperty, value);
}

/// <summary>
/// Gets or sets the ColumnAutoWidthMode for all columns.
/// </summary>
public TableViewColumnAutoWidthMode ColumnAutoWidthMode
{
get => (TableViewColumnAutoWidthMode)GetValue(ColumnAutoWidthModeProperty);
set => SetValue(ColumnAutoWidthModeProperty, value);
}

/// <summary>
/// Gets or sets the number of columns that stays in view on horizontal scroll.
/// </summary>
Expand Down Expand Up @@ -983,6 +997,17 @@ private static void OnCanFilterColumnsChanged(DependencyObject d, DependencyProp
}
}

/// <summary>
/// Handles changes to the ColumnAutoWidthMode property.
/// </summary>
private static void OnColumnAutoWidthModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TableView tableView)
{
tableView.RefreshColumnsAutoWidth();
}
}

/// <summary>
/// Handles changes to the MinColumnWidth property.
/// </summary>
Expand Down
32 changes: 32 additions & 0 deletions src/TableView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@
}
else
{
foreach (var propertyInfo in dataType.GetProperties())

Check warning on line 739 in src/TableView.cs

View workflow job for this annotation

GitHub Actions / build (x86)

'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperties()'. The return value of method 'WinUI.TableView.Extensions.ObjectExtensions.GetItemType(IEnumerable)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.

Check warning on line 739 in src/TableView.cs

View workflow job for this annotation

GitHub Actions / build (ARM64)

'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperties()'. The return value of method 'WinUI.TableView.Extensions.ObjectExtensions.GetItemType(IEnumerable)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
{
var displayAttribute = propertyInfo.GetCustomAttributes().OfType<DisplayAttribute>().FirstOrDefault();
var autoGenerateField = displayAttribute?.GetAutoGenerateField();
Expand Down Expand Up @@ -1867,6 +1867,38 @@
});
}

/// <summary>
/// Resets the auto-calculated widths of the specified columns and recalculates them.
/// </summary>
/// <param name="columns">The columns to refresh. When null, all columns are refreshed.</param>
internal void RefreshColumnsAutoWidth(IEnumerable<TableViewColumn>? columns = null)
{
var targetColumns = (columns ?? Columns).ToHashSet();
if (targetColumns.Count == 0)
{
return;
}

foreach (var column in targetColumns)
{
column.DesiredWidth = 0d;
column.HeaderControl?.InvalidateMeasure();
}

foreach (var row in _rows)
{
foreach (var cell in row.Cells)
{
if (cell.Column is { } cellColumn && targetColumns.Contains(cellColumn))
{
cell.InvalidateMeasure();
}
}
}

DispatcherQueue.TryEnqueue(() => _headerRow?.CalculateHeaderWidths());
}

/// <summary>
/// Ensures the column headers style is applied.
/// </summary>
Expand Down
26 changes: 15 additions & 11 deletions src/TableViewCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ void OnContentLoaded(object sender, RoutedEventArgs e)
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
if (Column is not null && Row is not null && _contentPresenter is not null && Content is FrameworkElement element)
if (TableView is not null && Column is not null && Row is not null && _contentPresenter is not null && Content is FrameworkElement element)
{
if (Column is TableViewTemplateColumn)
{
Expand All @@ -138,16 +138,20 @@ protected override Size MeasureOverride(Size availableSize)

element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

var desiredWidth = element.DesiredSize.Width;
desiredWidth += Padding.Left;
desiredWidth += Padding.Right;
desiredWidth += BorderThickness.Left;
desiredWidth += BorderThickness.Right;
desiredWidth += _selectionBorder?.BorderThickness.Right ?? 0;
desiredWidth += _selectionBorder?.BorderThickness.Left ?? 0;
desiredWidth += _v_gridLine?.ActualWidth ?? 0d;

Column.DesiredWidth = Math.Max(Column.DesiredWidth, desiredWidth);
var autoSizeMode = Column.ColumnAutoWidthMode ?? TableView.ColumnAutoWidthMode;
if (autoSizeMode is TableViewColumnAutoWidthMode.Cells or TableViewColumnAutoWidthMode.Both)
{
var desiredWidth = element.DesiredSize.Width;
desiredWidth += Padding.Left;
desiredWidth += Padding.Right;
desiredWidth += BorderThickness.Left;
desiredWidth += BorderThickness.Right;
desiredWidth += _selectionBorder?.BorderThickness.Right ?? 0;
desiredWidth += _selectionBorder?.BorderThickness.Left ?? 0;
desiredWidth += _v_gridLine?.ActualWidth ?? 0d;

Column.DesiredWidth = Math.Max(Column.DesiredWidth, desiredWidth);
}

#region TEMP_FIX_FOR_ISSUE https://github.com/microsoft/microsoft-ui-xaml/issues/9860
var contentWidth = Column.ActualWidth;
Expand Down
22 changes: 22 additions & 0 deletions src/TableViewColumnAutoWidthMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace WinUI.TableView;

/// <summary>
/// Specifies the behavior for automatic column width.
/// </summary>
public enum TableViewColumnAutoWidthMode
{
/// <summary>
/// Column width is adjusted to both header and maximum cell width.
/// </summary>
Both,

/// <summary>
/// Column width is adjusted to maximum cell width.
/// </summary>
Cells,

/// <summary>
/// Column width is adjusted to header width.
/// </summary>
Header
}
34 changes: 23 additions & 11 deletions src/TableViewColumnHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.System;
using Windows.UI.Core;
using WinUI.TableView.Collections;
Expand Down Expand Up @@ -63,7 +64,10 @@ public TableViewColumnHeader()
/// </summary>
private void OnWidthChanged(DependencyObject sender, DependencyProperty dp)
{
Column?.ActualWidth = Width;
if (!double.IsNaN(Width))
{
Column?.ActualWidth = Width;
}
}

/// <summary>
Expand Down Expand Up @@ -348,19 +352,11 @@ protected override void OnDoubleTapped(DoubleTappedRoutedEventArgs e)

if (position.X <= 8 && _headerRow?.GetPreviousHeader(this) is { Column: { } } header)
{
var width = Math.Clamp(
header.Column.DesiredWidth,
header.Column.MinWidth ?? _tableView.MinColumnWidth,
header.Column.MaxWidth ?? _tableView.MaxColumnWidth);
header.Column.Width = new GridLength(width, GridUnitType.Pixel);
header.Column.Width = GridLength.Auto;
Comment thread
w-ahmad marked this conversation as resolved.
}
else if (Column is not null)
{
var width = Math.Clamp(
Column.DesiredWidth,
Column.MinWidth ?? _tableView.MinColumnWidth,
Column.MaxWidth ?? _tableView.MaxColumnWidth);
Column.Width = new GridLength(width, GridUnitType.Pixel);
Column.Width = GridLength.Auto;
Comment thread
w-ahmad marked this conversation as resolved.
}
}

Expand Down Expand Up @@ -483,6 +479,22 @@ protected override void OnPointerReleased(PointerRoutedEventArgs e)
_reorderStarted = false;
}

/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
if (Column is not null && _tableView is not null)
{
var autoWidthMode = Column.ColumnAutoWidthMode ?? _tableView.ColumnAutoWidthMode;
if (autoWidthMode is TableViewColumnAutoWidthMode.Header or TableViewColumnAutoWidthMode.Both)
{
var desiredHeaderSize = base.MeasureOverride(new Size(double.PositiveInfinity, double.PositiveInfinity));
Column.DesiredWidth = Math.Max(Column.DesiredWidth, desiredHeaderSize.Width);
}
}

return base.MeasureOverride(availableSize);
}

/// <summary>
/// Ensures grid lines are applied.
/// </summary>
Expand Down
32 changes: 20 additions & 12 deletions src/TableViewHeaderRow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,19 +282,10 @@ internal void CalculateHeaderWidths()
var autoColumns = allColumns.Where(x => x.Width.IsAuto).ToList();
var absoluteColumns = allColumns.Where(x => x.Width.IsAbsolute).ToList();

var height = ActualHeight;
var availableWidth = TableView.ActualWidth - 32;
var starUnitWeight = starColumns.Select(x => x.Width.Value).Sum();
var fixedWidth = autoColumns.Select(x =>
{
if (x.HeaderControl is { } header)
{
header.Measure(new Size(double.PositiveInfinity, height));
return Math.Max(x.DesiredWidth, header.DesiredSize.Width);
}

return x.DesiredWidth;
}).Sum();
var fixedWidth = autoColumns.Select(GetColumnDesiredWidth).Sum();
fixedWidth += absoluteColumns.Select(x => x.ActualWidth).Sum();

availableWidth -= fixedWidth;
Expand Down Expand Up @@ -339,15 +330,14 @@ internal void CalculateHeaderWidths()
var width = column.Width.IsStar
? starUnitWidth * column.Width.Value
: column.Width.IsAbsolute ? column.Width.Value
: Math.Max(header.DesiredSize.Width, column.DesiredWidth);
: GetColumnDesiredWidth(column);

var minWidth = column.MinWidth ?? TableView.MinColumnWidth;
var maxWidth = column.MaxWidth ?? TableView.MaxColumnWidth;

width = width < minWidth ? minWidth : width;
width = width > maxWidth ? maxWidth : width;
header.Width = width;
header.MaxWidth = width;

DispatcherQueue.TryEnqueue(() =>
header.Measure(
Expand All @@ -362,6 +352,24 @@ internal void CalculateHeaderWidths()
}
}

/// <summary>
/// Gets the desired width of a column based on its header and cells.
/// </summary>
private double GetColumnDesiredWidth(TableViewColumn column)
{
var autoWidthMode = column.ColumnAutoWidthMode ?? TableView?.ColumnAutoWidthMode;
var width = column.DesiredWidth;

if (column.HeaderControl is { } header && autoWidthMode is not TableViewColumnAutoWidthMode.Cells)
{
header.Width = double.NaN;
header.Measure(new Size(double.PositiveInfinity, ActualHeight));
width = Math.Max(width, header.DesiredSize.Width);
}

return width;
}

/// <summary>
/// Handles the selection changed event for the TableView.
/// </summary>
Expand Down
Loading