From 2dbf05865cdd2e23cd614f5c44d85ccd322d31a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Tue, 28 Apr 2026 13:50:41 +0200 Subject: [PATCH 01/10] Make TableViewTemplateColumn use ClipboardContentBinding for copy and export --- src/Columns/TableViewColumn.cs | 9 +++++++-- src/Columns/TableViewTemplateColumn.cs | 6 ++++++ src/TableView.cs | 8 ++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Columns/TableViewColumn.cs b/src/Columns/TableViewColumn.cs index 48ae832a..defaa12b 100644 --- a/src/Columns/TableViewColumn.cs +++ b/src/Columns/TableViewColumn.cs @@ -120,8 +120,13 @@ internal void SetOwningTableView(TableView tableView) if (dataItem is null) return null; - if (_funcCompiledPropertyPath is null && !string.IsNullOrWhiteSpace(ClipboardContentBindingPropertyPath)) - _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(ClipboardContentBindingPropertyPath!); + if (_funcCompiledPropertyPath is null) + { + if (!string.IsNullOrWhiteSpace(ClipboardContentBindingPropertyPath)) + _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(ClipboardContentBindingPropertyPath!); + else + return null; + } if (_funcCompiledPropertyPath is not null) dataItem = _funcCompiledPropertyPath(dataItem); diff --git a/src/Columns/TableViewTemplateColumn.cs b/src/Columns/TableViewTemplateColumn.cs index da5d2dd1..9785dc69 100644 --- a/src/Columns/TableViewTemplateColumn.cs +++ b/src/Columns/TableViewTemplateColumn.cs @@ -64,6 +64,12 @@ public override void RefreshElement(TableViewCell cell, object? dataItem) cell.Content = GenerateElement(cell, dataItem); } + /// + public override object? GetCellContent(object? dataItem) + { + return GetClipboardContent(dataItem); + } + /// /// Gets or sets the DataTemplate for the cell content. /// diff --git a/src/TableView.cs b/src/TableView.cs index e21a6d3e..86f0f95f 100644 --- a/src/TableView.cs +++ b/src/TableView.cs @@ -283,7 +283,7 @@ protected async override void OnApplyTemplate() _scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer; _headerRowDefinition = GetTemplateChild("HeaderRowDefinition") as RowDefinition; if (_scrollViewer is not null) _scrollViewer.Loaded += OnScrollViewerLoaded; - + if (IsLoaded) { while (ItemsPanelRoot is null) await Task.Yield(); @@ -320,12 +320,12 @@ private void OnScrollViewerLoaded(object sender, RoutedEventArgs e) Source = this }); } - + /// /// Handles the Loaded event of the TableView control. /// private void OnLoaded(object sender, RoutedEventArgs e) - { + { EnsureAutoColumns(); } @@ -536,7 +536,7 @@ private string GetCellsContent(IEnumerable slots, bool includ for (var col = minColumn; col <= maxColumn; col++) { - if (Columns.VisibleColumns[col] is not TableViewBoundColumn column || + if (Columns.VisibleColumns[col] is not TableViewColumn column || !slots.Contains(new TableViewCellSlot(row, col))) { stringBuilder.Append(separator); From 4d3fa19621e8ec65a20708ec725a83aa7cfe655d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Tue, 28 Apr 2026 15:45:22 +0200 Subject: [PATCH 02/10] Add more navigation --- src/TableView.cs | 59 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/src/TableView.cs b/src/TableView.cs index e21a6d3e..f4e8a280 100644 --- a/src/TableView.cs +++ b/src/TableView.cs @@ -230,6 +230,59 @@ private async Task HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool c MakeSelection(newSlot, shiftKey); e.Handled = true; } + else if (e.Key == VirtualKey.Home) + { + var row = (ctrlKey ? 0 : CurrentCellSlot?.Row) ?? -1; + var column = 0; + + var newSlot = new TableViewCellSlot(row, column); + MakeSelection(newSlot, shiftKey); + e.Handled = true; + } + else if (e.Key == VirtualKey.End) + { + var row = (ctrlKey ? _collectionView.Count - 1 : CurrentCellSlot?.Row) ?? -1; + var column = Columns.VisibleColumns.Count - 1; + + var newSlot = new TableViewCellSlot(row, column); + MakeSelection(newSlot, shiftKey); + e.Handled = true; + } + else if (e.Key == VirtualKey.PageDown) + { + var pageSize = CalculateAvailablePageSize(); + + var row = (LastSelectionUnit is TableViewSelectionUnit.Row ? CurrentRowIndex : CurrentCellSlot?.Row) ?? -1; + var column = CurrentCellSlot?.Column ?? -1; + + var numRows = CollectionView.Count; + var nextRow = Math.Min(numRows - 1, row + pageSize); + + var newSlot = new TableViewCellSlot(nextRow, column); + MakeSelection(newSlot, shiftKey); + e.Handled = true; + } + else if (e.Key == VirtualKey.PageUp) + { + var pageSize = CalculateAvailablePageSize(); + + var row = (LastSelectionUnit is TableViewSelectionUnit.Row ? CurrentRowIndex : CurrentCellSlot?.Row) ?? -1; + var column = CurrentCellSlot?.Column ?? -1; + + var nextRow = Math.Max(0, row - pageSize); + + var newSlot = new TableViewCellSlot(nextRow, column); + MakeSelection(newSlot, shiftKey); + e.Handled = true; + } + } + + private int CalculateAvailablePageSize() + { + var rowHeight = RowHeight is not double.NaN ? RowHeight : RowMinHeight; + var headerHeight = HeaderRowHeight is not double.NaN ? HeaderRowHeight : HeaderRowMinHeight; + var availableHeight = ActualHeight - headerHeight; + return (int)Math.Floor(availableHeight / rowHeight); } internal bool EndCellEditing(TableViewEditAction editAction, TableViewCell cell) @@ -283,7 +336,7 @@ protected async override void OnApplyTemplate() _scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer; _headerRowDefinition = GetTemplateChild("HeaderRowDefinition") as RowDefinition; if (_scrollViewer is not null) _scrollViewer.Loaded += OnScrollViewerLoaded; - + if (IsLoaded) { while (ItemsPanelRoot is null) await Task.Yield(); @@ -320,12 +373,12 @@ private void OnScrollViewerLoaded(object sender, RoutedEventArgs e) Source = this }); } - + /// /// Handles the Loaded event of the TableView control. /// private void OnLoaded(object sender, RoutedEventArgs e) - { + { EnsureAutoColumns(); } From 8ca5d0ed736303abb91fdbfb4494428b49196191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Tue, 28 Apr 2026 16:12:03 +0200 Subject: [PATCH 03/10] End editing on PointerPress --- src/TableView.cs | 16 ++++++++-------- src/TableViewCell.cs | 39 +++++++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/TableView.cs b/src/TableView.cs index e21a6d3e..820ee410 100644 --- a/src/TableView.cs +++ b/src/TableView.cs @@ -133,7 +133,7 @@ protected override DependencyObject GetContainerForItemOverride() } /// - protected override async void OnKeyDown(KeyRoutedEventArgs e) + protected override void OnKeyDown(KeyRoutedEventArgs e) { var shiftKey = KeyboardHelper.IsShiftKeyDown(); var ctrlKey = KeyboardHelper.IsCtrlKeyDown(); @@ -144,19 +144,19 @@ protected override async void OnKeyDown(KeyRoutedEventArgs e) return; } - await HandleNavigations(e, shiftKey, ctrlKey); + HandleNavigations(e, shiftKey, ctrlKey); } /// /// Handles navigation keys. /// - private async Task HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool ctrlKey) + private void HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool ctrlKey) { var currentCell = CurrentCellSlot.HasValue ? GetCellFromSlot(CurrentCellSlot.Value) : default; if (e.Key is VirtualKey.F2 && currentCell is { IsReadOnly: false } && !IsEditing) { - e.Handled = await currentCell.BeginCellEditing(e); + e.Handled = currentCell.BeginCellEditing(e); } else if (e.Key is VirtualKey.Escape && currentCell is not null && IsEditing) { @@ -192,7 +192,7 @@ private async Task HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool c { if (!EndCellEditing(TableViewEditAction.Commit, currentCell)) return; - if (CurrentCellSlot == newSlot || GetCellFromSlot(newSlot) is not { } nextCell || !await nextCell.BeginCellEditing(e)) + if (CurrentCellSlot == newSlot || GetCellFromSlot(newSlot) is not { } nextCell || !nextCell.BeginCellEditing(e)) { SetIsEditing(false); } @@ -283,7 +283,7 @@ protected async override void OnApplyTemplate() _scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer; _headerRowDefinition = GetTemplateChild("HeaderRowDefinition") as RowDefinition; if (_scrollViewer is not null) _scrollViewer.Loaded += OnScrollViewerLoaded; - + if (IsLoaded) { while (ItemsPanelRoot is null) await Task.Yield(); @@ -320,12 +320,12 @@ private void OnScrollViewerLoaded(object sender, RoutedEventArgs e) Source = this }); } - + /// /// Handles the Loaded event of the TableView control. /// private void OnLoaded(object sender, RoutedEventArgs e) - { + { EnsureAutoColumns(); } diff --git a/src/TableViewCell.cs b/src/TableViewCell.cs index 758c3b14..097210f1 100644 --- a/src/TableViewCell.cs +++ b/src/TableViewCell.cs @@ -210,18 +210,14 @@ protected override void OnPointerExited(PointerRoutedEventArgs e) } /// - protected override async void OnTapped(TappedRoutedEventArgs e) + protected override void OnTapped(TappedRoutedEventArgs e) { base.OnTapped(e); - if ((TableView?.IsEditing ?? false) && - TableView.CurrentCellSlot != Slot && - TableView.CurrentCellSlot.HasValue && - TableView.GetCellFromSlot(TableView.CurrentCellSlot.Value) is { } currentCell) + if (TryEndCurrentCellEdit()) { - e.Handled = !TableView.EndCellEditing(TableViewEditAction.Commit, currentCell); - - if (e.Handled) return; + e.Handled = true; + return; } if (TableView?.CurrentCellSlot != Slot || TableView?.LastSelectionUnit is TableViewSelectionUnit.Row) @@ -236,9 +232,15 @@ protected override void OnPointerPressed(PointerRoutedEventArgs e) { base.OnPointerPressed(e); + if (TryEndCurrentCellEdit()) + { + e.Handled = true; + return; + } + if (!KeyboardHelper.IsShiftKeyDown() && TableView is not null) { - TableView.SelectionStartCellSlot = TableView.SelectionUnit is not TableViewSelectionUnit.Row || !IsReadOnly ? Slot : default; ; + TableView.SelectionStartCellSlot = TableView.SelectionUnit is not TableViewSelectionUnit.Row || !IsReadOnly ? Slot : default; TableView.SelectionStartRowIndex = Index; CapturePointer(e.Pointer); } @@ -278,6 +280,19 @@ protected override void OnManipulationDelta(ManipulationDeltaRoutedEventArgs e) } } + private bool TryEndCurrentCellEdit() + { + if ((TableView?.IsEditing ?? false) && + TableView.CurrentCellSlot != Slot && + TableView.CurrentCellSlot.HasValue && + TableView.GetCellFromSlot(TableView.CurrentCellSlot.Value) is { } currentCell) + { + return !TableView.EndCellEditing(TableViewEditAction.Commit, currentCell); + } + + return false; + } + /// /// Gets the height of the horizontal gridlines/>. /// @@ -309,7 +324,7 @@ private double GetHorizontalGridlineHeight() } /// - protected override async void OnDoubleTapped(DoubleTappedRoutedEventArgs e) + protected override void OnDoubleTapped(DoubleTappedRoutedEventArgs e) { var eventArgs = new TableViewCellDoubleTappedEventArgs(Slot, this, Row?.Content); TableView?.OnCellDoubleTapped(eventArgs); @@ -321,7 +336,7 @@ protected override async void OnDoubleTapped(DoubleTappedRoutedEventArgs e) if (!IsReadOnly && TableView is not null && !TableView.IsEditing && !Column?.UseSingleElement is true) { - e.Handled = await BeginCellEditing(e); + e.Handled = BeginCellEditing(e); } else { @@ -370,7 +385,7 @@ private void MakeSelection() /// The event data associated with the editing request. Cannot be null. /// A task that represents the asynchronous operation. The task result is if cell editing was /// successfully started; otherwise, if the operation was canceled. - internal async Task BeginCellEditing(RoutedEventArgs editingArgs) + internal bool BeginCellEditing(RoutedEventArgs editingArgs) { var args = new TableViewBeginningEditEventArgs(this, Row?.Content, Column!, editingArgs); TableView?.OnBeginningEdit(args); From f1486e8859bb83ffd2578b0687eeb76bce6b1807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Mon, 4 May 2026 08:05:50 +0200 Subject: [PATCH 04/10] Add OperationContentBinding to TableViewTemplateColumn to provide an option to use a binding for sorting, exporting, filtering --- src/Columns/TableViewTemplateColumn.cs | 51 +++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Columns/TableViewTemplateColumn.cs b/src/Columns/TableViewTemplateColumn.cs index 9785dc69..30fc1ce9 100644 --- a/src/Columns/TableViewTemplateColumn.cs +++ b/src/Columns/TableViewTemplateColumn.cs @@ -1,5 +1,8 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Data; +using System; +using WinUI.TableView.Extensions; namespace WinUI.TableView; @@ -11,6 +14,8 @@ namespace WinUI.TableView; #endif public partial class TableViewTemplateColumn : TableViewColumn { + private Func? _funcCompiledPropertyPath; + /// /// Initializes a new instance of the TableViewTemplateColumn class. /// @@ -67,7 +72,30 @@ public override void RefreshElement(TableViewCell cell, object? dataItem) /// public override object? GetCellContent(object? dataItem) { - return GetClipboardContent(dataItem); + if (dataItem is null) + return null; + + if (_funcCompiledPropertyPath is null) + { + if (!string.IsNullOrWhiteSpace(OperationContentBindingPropertyPath)) + _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(OperationContentBindingPropertyPath!); + else + return null; + } + + if (_funcCompiledPropertyPath is not null) + dataItem = _funcCompiledPropertyPath(dataItem); + + if (OperationContentBinding?.Converter is not null) + { + dataItem = OperationContentBinding.Converter.Convert( + dataItem, + typeof(object), + OperationContentBinding.ConverterParameter, + OperationContentBinding.ConverterLanguage); + } + + return dataItem; } /// @@ -106,6 +134,27 @@ public DataTemplateSelector? EditingTemplateSelector set => SetValue(EditingTemplateSelectorProperty, value); } + /// + /// Gets or sets the optional data binding used to perform operations on cell content, for example sorting, filtering and exporting. + /// Is not used in the CellTemplate or EditingTemplate. + /// + public Binding? OperationContentBinding { get; set; } + + /// + /// Gets the property path for the . + /// + internal string? OperationContentBindingPropertyPath => OperationContentBinding?.Path?.Path; + + /// + /// Gets or sets the data binding used to retrieve cell content when copying to the clipboard. + /// If no explicit clipboard binding is set, the column's is returned as a fallback. + /// + public override Binding? ClipboardContentBinding + { + get => base.ClipboardContentBinding ?? OperationContentBinding; + set => base.ClipboardContentBinding = value; + } + /// /// Identifies the CellTemplate dependency property. /// From a0cbf47afe9b39f77fc8267ec6b654b9ccee614f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Wed, 6 May 2026 17:41:47 +0200 Subject: [PATCH 05/10] Merge logic and add comment --- src/TableView.cs | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/src/TableView.cs b/src/TableView.cs index f4e8a280..4d8b3afc 100644 --- a/src/TableView.cs +++ b/src/TableView.cs @@ -230,25 +230,16 @@ private async Task HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool c MakeSelection(newSlot, shiftKey); e.Handled = true; } - else if (e.Key == VirtualKey.Home) + else if (e.Key is VirtualKey.Home or VirtualKey.End) { - var row = (ctrlKey ? 0 : CurrentCellSlot?.Row) ?? -1; - var column = 0; + var row = ctrlKey ? (e.Key == VirtualKey.Home ? 0 : _collectionView.Count - 1) : CurrentCellSlot?.Row; + var column = e.Key == VirtualKey.Home ? 0 : Columns.VisibleColumns.Count - 1; - var newSlot = new TableViewCellSlot(row, column); - MakeSelection(newSlot, shiftKey); - e.Handled = true; - } - else if (e.Key == VirtualKey.End) - { - var row = (ctrlKey ? _collectionView.Count - 1 : CurrentCellSlot?.Row) ?? -1; - var column = Columns.VisibleColumns.Count - 1; - - var newSlot = new TableViewCellSlot(row, column); + var newSlot = new TableViewCellSlot(row ?? -1, column); MakeSelection(newSlot, shiftKey); e.Handled = true; } - else if (e.Key == VirtualKey.PageDown) + else if (e.Key is VirtualKey.PageDown or VirtualKey.PageUp) { var pageSize = CalculateAvailablePageSize(); @@ -256,20 +247,9 @@ private async Task HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool c var column = CurrentCellSlot?.Column ?? -1; var numRows = CollectionView.Count; - var nextRow = Math.Min(numRows - 1, row + pageSize); - - var newSlot = new TableViewCellSlot(nextRow, column); - MakeSelection(newSlot, shiftKey); - e.Handled = true; - } - else if (e.Key == VirtualKey.PageUp) - { - var pageSize = CalculateAvailablePageSize(); - - var row = (LastSelectionUnit is TableViewSelectionUnit.Row ? CurrentRowIndex : CurrentCellSlot?.Row) ?? -1; - var column = CurrentCellSlot?.Column ?? -1; - - var nextRow = Math.Max(0, row - pageSize); + var nextRow = e.Key == VirtualKey.PageDown + ? Math.Min(numRows - 1, row + pageSize) + : Math.Max(0, row - pageSize); var newSlot = new TableViewCellSlot(nextRow, column); MakeSelection(newSlot, shiftKey); @@ -277,6 +257,9 @@ private async Task HandleNavigations(KeyRoutedEventArgs e, bool shiftKey, bool c } } + /// + /// Calculates how many rows should be able to fit within the actual height of the table without scrolling. + /// private int CalculateAvailablePageSize() { var rowHeight = RowHeight is not double.NaN ? RowHeight : RowMinHeight; From 51a0cf5d507fa839b66f3aeeb183dcd8bca68f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Thu, 7 May 2026 18:23:29 +0200 Subject: [PATCH 06/10] Move functionality to TableViewColumn --- src/Columns/TableViewBoundColumn.cs | 39 +++--------------- src/Columns/TableViewColumn.cs | 52 ++++++++++++++++++------ src/Columns/TableViewTemplateColumn.cs | 55 -------------------------- 3 files changed, 46 insertions(+), 100 deletions(-) diff --git a/src/Columns/TableViewBoundColumn.cs b/src/Columns/TableViewBoundColumn.cs index 39673298..274a7997 100644 --- a/src/Columns/TableViewBoundColumn.cs +++ b/src/Columns/TableViewBoundColumn.cs @@ -1,9 +1,5 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Data; -using System; -using System.Linq.Expressions; -using System.Reflection; -using WinUI.TableView.Extensions; namespace WinUI.TableView; @@ -13,31 +9,6 @@ namespace WinUI.TableView; public abstract class TableViewBoundColumn : TableViewColumn { private Binding _binding = new(); - private Func? _funcCompiledPropertyPath; - - /// - public override object? GetCellContent(object? dataItem) - { - if (dataItem is null) - return null; - - if (_funcCompiledPropertyPath is null && !string.IsNullOrWhiteSpace(PropertyPath)) - _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(PropertyPath!); - - if (_funcCompiledPropertyPath is not null) - dataItem = _funcCompiledPropertyPath(dataItem); - - if (Binding?.Converter is not null) - { - dataItem = Binding.Converter.Convert( - dataItem, - typeof(object), - Binding.ConverterParameter, - Binding.ConverterLanguage); - } - - return dataItem; - } /// /// Gets the property path for the binding. @@ -70,13 +41,13 @@ public virtual Binding Binding } /// - /// Gets or sets the data binding used to retrieve cell content when copying to the clipboard. - /// If no explicit clipboard binding is set, the column's is returned as a fallback. + /// Gets or sets the optional data binding used to perform operations on cell content, for example sorting, filtering and exporting. + /// If no explicit operation binding is set, the column's is returned as a fallback. /// - public override Binding? ClipboardContentBinding + public override Binding? OperationContentBinding { - get => base.ClipboardContentBinding ?? Binding; - set => base.ClipboardContentBinding = value; + get => base.OperationContentBinding ?? Binding; + set => base.OperationContentBinding = value; } /// diff --git a/src/Columns/TableViewColumn.cs b/src/Columns/TableViewColumn.cs index defaa12b..b145f637 100644 --- a/src/Columns/TableViewColumn.cs +++ b/src/Columns/TableViewColumn.cs @@ -20,6 +20,8 @@ public abstract partial class TableViewColumn : DependencyObject private bool _isFiltered; private bool _isFrozen; private Func? _funcCompiledPropertyPath; + private Func? _funcCompiledClipboardPropertyPath; + private Binding? _clipboardContentBinding; /// /// Initializes a new instance of the class with default conditional cell styles. @@ -107,7 +109,25 @@ internal void SetOwningTableView(TableView tableView) /// The content of the cell. public virtual object? GetCellContent(object? dataItem) { - return default; + if (dataItem is null) + return null; + + if (_funcCompiledPropertyPath is null && !string.IsNullOrWhiteSpace(OperationContentBindingPropertyPath)) + _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(OperationContentBindingPropertyPath!); + + if (_funcCompiledPropertyPath is not null) + dataItem = _funcCompiledPropertyPath(dataItem); + + if (OperationContentBinding?.Converter is not null) + { + dataItem = OperationContentBinding.Converter.Convert( + dataItem, + typeof(object), + OperationContentBinding.ConverterParameter, + OperationContentBinding.ConverterLanguage); + } + + return dataItem; } /// @@ -120,16 +140,11 @@ internal void SetOwningTableView(TableView tableView) if (dataItem is null) return null; - if (_funcCompiledPropertyPath is null) - { - if (!string.IsNullOrWhiteSpace(ClipboardContentBindingPropertyPath)) - _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(ClipboardContentBindingPropertyPath!); - else - return null; - } + if (_funcCompiledClipboardPropertyPath is null && !string.IsNullOrWhiteSpace(ClipboardContentBindingPropertyPath)) + _funcCompiledClipboardPropertyPath = dataItem.GetFuncCompiledPropertyPath(ClipboardContentBindingPropertyPath!); - if (_funcCompiledPropertyPath is not null) - dataItem = _funcCompiledPropertyPath(dataItem); + if (_funcCompiledClipboardPropertyPath is not null) + dataItem = _funcCompiledClipboardPropertyPath(dataItem); if (ClipboardContentBinding?.Converter is not null) { @@ -370,10 +385,25 @@ internal set } } + /// + /// Gets or sets the optional data binding used to perform operations on cell content, for example sorting, filtering and exporting. + /// + public virtual Binding? OperationContentBinding { get; set; } + + /// + /// Gets the property path for the . + /// + internal string? OperationContentBindingPropertyPath => OperationContentBinding?.Path?.Path; + /// /// Gets or sets the data binding used to retrieve cell content when copying to the clipboard. + /// If no explicit clipboard binding is set, the column's is returned as a fallback. /// - public virtual Binding? ClipboardContentBinding { get; set; } + public Binding? ClipboardContentBinding + { + get => _clipboardContentBinding ?? OperationContentBinding; + set => _clipboardContentBinding = value; + } /// /// Gets the property path for the . diff --git a/src/Columns/TableViewTemplateColumn.cs b/src/Columns/TableViewTemplateColumn.cs index 30fc1ce9..da5d2dd1 100644 --- a/src/Columns/TableViewTemplateColumn.cs +++ b/src/Columns/TableViewTemplateColumn.cs @@ -1,8 +1,5 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Data; -using System; -using WinUI.TableView.Extensions; namespace WinUI.TableView; @@ -14,8 +11,6 @@ namespace WinUI.TableView; #endif public partial class TableViewTemplateColumn : TableViewColumn { - private Func? _funcCompiledPropertyPath; - /// /// Initializes a new instance of the TableViewTemplateColumn class. /// @@ -69,35 +64,6 @@ public override void RefreshElement(TableViewCell cell, object? dataItem) cell.Content = GenerateElement(cell, dataItem); } - /// - public override object? GetCellContent(object? dataItem) - { - if (dataItem is null) - return null; - - if (_funcCompiledPropertyPath is null) - { - if (!string.IsNullOrWhiteSpace(OperationContentBindingPropertyPath)) - _funcCompiledPropertyPath = dataItem.GetFuncCompiledPropertyPath(OperationContentBindingPropertyPath!); - else - return null; - } - - if (_funcCompiledPropertyPath is not null) - dataItem = _funcCompiledPropertyPath(dataItem); - - if (OperationContentBinding?.Converter is not null) - { - dataItem = OperationContentBinding.Converter.Convert( - dataItem, - typeof(object), - OperationContentBinding.ConverterParameter, - OperationContentBinding.ConverterLanguage); - } - - return dataItem; - } - /// /// Gets or sets the DataTemplate for the cell content. /// @@ -134,27 +100,6 @@ public DataTemplateSelector? EditingTemplateSelector set => SetValue(EditingTemplateSelectorProperty, value); } - /// - /// Gets or sets the optional data binding used to perform operations on cell content, for example sorting, filtering and exporting. - /// Is not used in the CellTemplate or EditingTemplate. - /// - public Binding? OperationContentBinding { get; set; } - - /// - /// Gets the property path for the . - /// - internal string? OperationContentBindingPropertyPath => OperationContentBinding?.Path?.Path; - - /// - /// Gets or sets the data binding used to retrieve cell content when copying to the clipboard. - /// If no explicit clipboard binding is set, the column's is returned as a fallback. - /// - public override Binding? ClipboardContentBinding - { - get => base.ClipboardContentBinding ?? OperationContentBinding; - set => base.ClipboardContentBinding = value; - } - /// /// Identifies the CellTemplate dependency property. /// From 15847589ac9d281502c9b033bca4534fb097f080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Thu, 7 May 2026 19:13:54 +0200 Subject: [PATCH 07/10] Set TableView.IsEditing flag --- src/TableViewCell.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/TableViewCell.cs b/src/TableViewCell.cs index 097210f1..a2f233de 100644 --- a/src/TableViewCell.cs +++ b/src/TableViewCell.cs @@ -287,7 +287,9 @@ private bool TryEndCurrentCellEdit() TableView.CurrentCellSlot.HasValue && TableView.GetCellFromSlot(TableView.CurrentCellSlot.Value) is { } currentCell) { - return !TableView.EndCellEditing(TableViewEditAction.Commit, currentCell); + if (!TableView.EndCellEditing(TableViewEditAction.Commit, currentCell)) return true; + + TableView.SetIsEditing(false); } return false; From df718d1272b02926c83c78542a56efdfebf9acd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Torsg=C3=A5rden?= Date: Fri, 8 May 2026 09:28:50 +0200 Subject: [PATCH 08/10] Invert TryEndCurrentCellEdit return value --- src/TableViewCell.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/TableViewCell.cs b/src/TableViewCell.cs index a2f233de..af37ac0e 100644 --- a/src/TableViewCell.cs +++ b/src/TableViewCell.cs @@ -214,7 +214,7 @@ protected override void OnTapped(TappedRoutedEventArgs e) { base.OnTapped(e); - if (TryEndCurrentCellEdit()) + if (!TryEndCurrentCellEdit()) { e.Handled = true; return; @@ -232,7 +232,7 @@ protected override void OnPointerPressed(PointerRoutedEventArgs e) { base.OnPointerPressed(e); - if (TryEndCurrentCellEdit()) + if (!TryEndCurrentCellEdit()) { e.Handled = true; return; @@ -280,6 +280,11 @@ protected override void OnManipulationDelta(ManipulationDeltaRoutedEventArgs e) } } + /// + /// Tries to end the current edit operation, if any. + /// + /// True if an edit operation was successfully ended, or there is no edit operation. + /// False if the current edit operation can not be ended. private bool TryEndCurrentCellEdit() { if ((TableView?.IsEditing ?? false) && @@ -287,12 +292,12 @@ private bool TryEndCurrentCellEdit() TableView.CurrentCellSlot.HasValue && TableView.GetCellFromSlot(TableView.CurrentCellSlot.Value) is { } currentCell) { - if (!TableView.EndCellEditing(TableViewEditAction.Commit, currentCell)) return true; + if (!TableView.EndCellEditing(TableViewEditAction.Commit, currentCell)) return false; TableView.SetIsEditing(false); } - return false; + return true; } /// From a9670c75dfaf243db41f4b6086af2e06bbcb15d6 Mon Sep 17 00:00:00 2001 From: Waheed Ahmad Date: Tue, 12 May 2026 20:45:30 +0500 Subject: [PATCH 09/10] add ContentProperty attribute to template column --- src/Columns/TableViewTemplateColumn.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Columns/TableViewTemplateColumn.cs b/src/Columns/TableViewTemplateColumn.cs index da5d2dd1..e7121ccb 100644 --- a/src/Columns/TableViewTemplateColumn.cs +++ b/src/Columns/TableViewTemplateColumn.cs @@ -9,6 +9,7 @@ namespace WinUI.TableView; #if WINDOWS [WinRT.GeneratedBindableCustomProperty] #endif +[ContentProperty(Name = nameof(CellTemplate))] public partial class TableViewTemplateColumn : TableViewColumn { /// From e1197c37dfbd21c6f6e09f8e17a03a6cfece7861 Mon Sep 17 00:00:00 2001 From: Waheed Ahmad Date: Tue, 12 May 2026 21:14:44 +0500 Subject: [PATCH 10/10] added using --- src/Columns/TableViewTemplateColumn.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Columns/TableViewTemplateColumn.cs b/src/Columns/TableViewTemplateColumn.cs index e7121ccb..044fc192 100644 --- a/src/Columns/TableViewTemplateColumn.cs +++ b/src/Columns/TableViewTemplateColumn.cs @@ -1,5 +1,6 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Markup; namespace WinUI.TableView;