diff --git a/samples/WinUI.TableView.SampleApp/MainPage.xaml.cs b/samples/WinUI.TableView.SampleApp/MainPage.xaml.cs
index 5d0b5e8..f8debb5 100644
--- a/samples/WinUI.TableView.SampleApp/MainPage.xaml.cs
+++ b/samples/WinUI.TableView.SampleApp/MainPage.xaml.cs
@@ -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)
};
diff --git a/samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml b/samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml
new file mode 100644
index 0000000..48ee037
--- /dev/null
+++ b/samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<tv:TableView ItemsSource="{Binding Items}"
+ ColumnAutoWidthMode="$(ColumnAutoWidthMode)"/>
+
+
+
+
+
+
+
+
diff --git a/samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml.cs b/samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml.cs
new file mode 100644
index 0000000..8c60f26
--- /dev/null
+++ b/samples/WinUI.TableView.SampleApp/Pages/ColumnSizingPage.xaml.cs
@@ -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)];
+ }
+}
\ No newline at end of file
diff --git a/src/Columns/TableViewColumn.cs b/src/Columns/TableViewColumn.cs
index 572c71d..25a7342 100644
--- a/src/Columns/TableViewColumn.cs
+++ b/src/Columns/TableViewColumn.cs
@@ -237,6 +237,15 @@ public double ActualWidth
set => SetValue(ActualWidthProperty, value);
}
+ ///
+ /// Gets or sets the ColumnAutoWidthMode of the column.
+ ///
+ public TableViewColumnAutoWidthMode? ColumnAutoWidthMode
+ {
+ get => (TableViewColumnAutoWidthMode?)GetValue(ColumnAutoWidthModeProperty);
+ set => SetValue(ColumnAutoWidthModeProperty, value);
+ }
+
///
/// Gets or sets a value indicating whether the column can be resized.
///
@@ -508,6 +517,17 @@ private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChan
}
}
+ ///
+ /// Handles changes to the ColumnAutoWidthMode property.
+ ///
+ private static void OnColumnAutoWidthModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is TableViewColumn column)
+ {
+ column.TableView?.RefreshColumnsAutoWidth([column]);
+ }
+ }
+
///
/// Handles changes to the CanFilter property.
///
@@ -579,6 +599,11 @@ public string? SortMemberPath
///
public static readonly DependencyProperty ActualWidthProperty = DependencyProperty.Register(nameof(ActualWidth), typeof(double), typeof(TableViewColumn), new PropertyMetadata(0d, OnPropertyChanged));
+ ///
+ /// Identifies the ColumnAutoWidthMode dependency property.
+ ///
+ public static readonly DependencyProperty ColumnAutoWidthModeProperty = DependencyProperty.Register(nameof(ColumnAutoWidthMode), typeof(TableViewColumnAutoWidthMode?), typeof(TableViewColumn), new PropertyMetadata(null, OnColumnAutoWidthModeChanged));
+
///
/// Identifies the CanResize dependency property.
///
diff --git a/src/TableView.Properties.cs b/src/TableView.Properties.cs
index 8b6fc07..761241f 100644
--- a/src/TableView.Properties.cs
+++ b/src/TableView.Properties.cs
@@ -221,6 +221,11 @@ public partial class TableView
///
public static readonly DependencyProperty RowHeaderTemplateSelectorProperty = DependencyProperty.Register(nameof(RowHeaderTemplateSelector), typeof(DataTemplateSelector), typeof(TableView), new PropertyMetadata(null, OnRowHeaderTemplateChanged));
+ ///
+ /// Identifies the ColumnAutoWidthMode dependency property.
+ ///
+ public static readonly DependencyProperty ColumnAutoWidthModeProperty = DependencyProperty.Register(nameof(ColumnAutoWidthMode), typeof(TableViewColumnAutoWidthMode), typeof(TableView), new PropertyMetadata(TableViewColumnAutoWidthMode.Both, OnColumnAutoWidthModeChanged));
+
///
/// Identifies the FrozenColumnCount dependency property.
///
@@ -792,6 +797,15 @@ public DataTemplateSelector? RowHeaderTemplateSelector
set => SetValue(RowHeaderTemplateSelectorProperty, value);
}
+ ///
+ /// Gets or sets the ColumnAutoWidthMode for all columns.
+ ///
+ public TableViewColumnAutoWidthMode ColumnAutoWidthMode
+ {
+ get => (TableViewColumnAutoWidthMode)GetValue(ColumnAutoWidthModeProperty);
+ set => SetValue(ColumnAutoWidthModeProperty, value);
+ }
+
///
/// Gets or sets the number of columns that stays in view on horizontal scroll.
///
@@ -983,6 +997,17 @@ private static void OnCanFilterColumnsChanged(DependencyObject d, DependencyProp
}
}
+ ///
+ /// Handles changes to the ColumnAutoWidthMode property.
+ ///
+ private static void OnColumnAutoWidthModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is TableView tableView)
+ {
+ tableView.RefreshColumnsAutoWidth();
+ }
+ }
+
///
/// Handles changes to the MinColumnWidth property.
///
diff --git a/src/TableView.cs b/src/TableView.cs
index 206d74e..1b50492 100644
--- a/src/TableView.cs
+++ b/src/TableView.cs
@@ -1867,6 +1867,38 @@ internal void EnsureAlternateRowColors()
});
}
+ ///
+ /// Resets the auto-calculated widths of the specified columns and recalculates them.
+ ///
+ /// The columns to refresh. When null, all columns are refreshed.
+ internal void RefreshColumnsAutoWidth(IEnumerable? 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());
+ }
+
///
/// Ensures the column headers style is applied.
///
diff --git a/src/TableViewCell.cs b/src/TableViewCell.cs
index bed74cc..0a427b0 100644
--- a/src/TableViewCell.cs
+++ b/src/TableViewCell.cs
@@ -117,7 +117,7 @@ void OnContentLoaded(object sender, RoutedEventArgs e)
///
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)
{
@@ -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;
diff --git a/src/TableViewColumnAutoWidthMode.cs b/src/TableViewColumnAutoWidthMode.cs
new file mode 100644
index 0000000..662c6bf
--- /dev/null
+++ b/src/TableViewColumnAutoWidthMode.cs
@@ -0,0 +1,22 @@
+namespace WinUI.TableView;
+
+///
+/// Specifies the behavior for automatic column width.
+///
+public enum TableViewColumnAutoWidthMode
+{
+ ///
+ /// Column width is adjusted to both header and maximum cell width.
+ ///
+ Both,
+
+ ///
+ /// Column width is adjusted to maximum cell width.
+ ///
+ Cells,
+
+ ///
+ /// Column width is adjusted to header width.
+ ///
+ Header
+}
diff --git a/src/TableViewColumnHeader.cs b/src/TableViewColumnHeader.cs
index 0302952..996657d 100644
--- a/src/TableViewColumnHeader.cs
+++ b/src/TableViewColumnHeader.cs
@@ -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;
@@ -63,7 +64,10 @@ public TableViewColumnHeader()
///
private void OnWidthChanged(DependencyObject sender, DependencyProperty dp)
{
- Column?.ActualWidth = Width;
+ if (!double.IsNaN(Width))
+ {
+ Column?.ActualWidth = Width;
+ }
}
///
@@ -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;
}
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;
}
}
@@ -483,6 +479,22 @@ protected override void OnPointerReleased(PointerRoutedEventArgs e)
_reorderStarted = false;
}
+ ///
+ 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);
+ }
+
///
/// Ensures grid lines are applied.
///
diff --git a/src/TableViewHeaderRow.cs b/src/TableViewHeaderRow.cs
index 6aed1b7..d648b5a 100644
--- a/src/TableViewHeaderRow.cs
+++ b/src/TableViewHeaderRow.cs
@@ -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;
@@ -339,7 +330,7 @@ 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;
@@ -347,7 +338,6 @@ internal void CalculateHeaderWidths()
width = width < minWidth ? minWidth : width;
width = width > maxWidth ? maxWidth : width;
header.Width = width;
- header.MaxWidth = width;
DispatcherQueue.TryEnqueue(() =>
header.Measure(
@@ -362,6 +352,24 @@ internal void CalculateHeaderWidths()
}
}
+ ///
+ /// Gets the desired width of a column based on its header and cells.
+ ///
+ 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;
+ }
+
///
/// Handles the selection changed event for the TableView.
///