diff --git a/src/ColumnFilterHandler.cs b/src/ColumnFilterHandler.cs
index 8a1b67f3..abfa32a9 100644
--- a/src/ColumnFilterHandler.cs
+++ b/src/ColumnFilterHandler.cs
@@ -144,10 +144,7 @@ public virtual void ClearFilter(TableViewColumn? column)
foreach (var col in _tableView.Columns)
{
- if (col is not null)
- {
- col.IsFiltered = false;
- }
+ col?.IsFiltered = false;
}
}
}
diff --git a/src/Columns/TableViewBoundColumn.cs b/src/Columns/TableViewBoundColumn.cs
index 274a7997..f6bf5a7d 100644
--- a/src/Columns/TableViewBoundColumn.cs
+++ b/src/Columns/TableViewBoundColumn.cs
@@ -8,8 +8,6 @@ namespace WinUI.TableView;
///
public abstract class TableViewBoundColumn : TableViewColumn
{
- private Binding _binding = new();
-
///
/// Gets the property path for the binding.
///
@@ -20,10 +18,10 @@ public abstract class TableViewBoundColumn : TableViewColumn
///
public virtual Binding Binding
{
- get => _binding;
+ get;
set
{
- if (_binding != value)
+ if (field != value)
{
if (value is not null)
{
@@ -35,10 +33,10 @@ public virtual Binding Binding
}
}
- _binding = value!;
+ field = value!;
}
}
- }
+ } = new();
///
/// Gets or sets the optional data binding used to perform operations on cell content, for example sorting, filtering and exporting.
diff --git a/src/Columns/TableViewColumn.cs b/src/Columns/TableViewColumn.cs
index b145f637..494aa2b6 100644
--- a/src/Columns/TableViewColumn.cs
+++ b/src/Columns/TableViewColumn.cs
@@ -14,14 +14,8 @@ namespace WinUI.TableView;
[StyleTypedProperty(Property = nameof(CellStyle), StyleTargetType = typeof(TableViewCell))]
public abstract partial class TableViewColumn : DependencyObject
{
- private TableViewColumnHeader? _headerControl;
- private double _desiredWidth;
- private SD? _sortDirection;
- private bool _isFiltered;
- private bool _isFrozen;
private Func
internal double DesiredWidth
{
- get => _desiredWidth;
+ get;
set
{
- if (_desiredWidth != value)
+ if (field != value)
{
- _desiredWidth = value;
+ field = value;
OwningCollection?.HandleColumnPropertyChanged(this, nameof(DesiredWidth));
}
}
@@ -348,11 +345,14 @@ internal double DesiredWidth
///
public SD? SortDirection
{
- get => _sortDirection;
+ get;
set
{
- _sortDirection = value;
- OnSortDirectionChanged();
+ if (field != value)
+ {
+ field = value;
+ OnSortDirectionChanged();
+ }
}
}
@@ -361,11 +361,14 @@ public SD? SortDirection
///
public bool IsFiltered
{
- get => _isFiltered;
+ get;
set
{
- _isFiltered = value;
- OnIsFilteredChanged();
+ if (field != value)
+ {
+ field = value;
+ OnIsFilteredChanged();
+ }
}
}
@@ -374,12 +377,12 @@ public bool IsFiltered
///
public bool IsFrozen
{
- get => _isFrozen;
+ get;
internal set
{
- if (_isFrozen != value)
+ if (field != value)
{
- _isFrozen = value;
+ field = value;
OwningCollection?.HandleColumnPropertyChanged(this, nameof(IsFrozen));
}
}
@@ -401,8 +404,8 @@ internal set
///
public Binding? ClipboardContentBinding
{
- get => _clipboardContentBinding ?? OperationContentBinding;
- set => _clipboardContentBinding = value;
+ get => field ?? OperationContentBinding;
+ set;
}
///
@@ -436,10 +439,7 @@ private void OnIsFilteredChanged()
///
internal void EnsureHeaderStyle()
{
- if (_headerControl is not null)
- {
- _headerControl.Style = HeaderStyle ?? TableView?.ColumnHeaderStyle;
- }
+ HeaderControl?.Style = HeaderStyle ?? TableView?.ColumnHeaderStyle;
}
///
diff --git a/src/Columns/TableViewComboBoxColumn.cs b/src/Columns/TableViewComboBoxColumn.cs
index dcd4472e..18e073dc 100644
--- a/src/Columns/TableViewComboBoxColumn.cs
+++ b/src/Columns/TableViewComboBoxColumn.cs
@@ -15,9 +15,6 @@ namespace WinUI.TableView;
#endif
public partial class TableViewComboBoxColumn : TableViewBoundColumn
{
- private Binding? _textBinding;
- private Binding? _selectedValueBinding;
-
///
/// Generates a TextBlock element for the cell.
///
@@ -135,32 +132,26 @@ public bool IsEditable
///
/// Gets or sets the binding for the text property of the ComboBox.
///
- public virtual Binding TextBinding
+ public virtual Binding? TextBinding
{
- get => _textBinding!;
+ get;
set
{
- _textBinding = value;
- if (_textBinding is not null)
- {
- _textBinding.Mode = BindingMode.TwoWay;
- }
+ field = value;
+ field?.Mode = BindingMode.TwoWay;
}
}
///
/// Gets or sets the binding for the selected value property of the ComboBox.
///
- public virtual Binding SelectedValueBinding
+ public virtual Binding? SelectedValueBinding
{
- get => _selectedValueBinding!;
+ get;
set
{
- _selectedValueBinding = value;
- if (_selectedValueBinding is not null)
- {
- _selectedValueBinding.Mode = BindingMode.TwoWay;
- }
+ field = value;
+ field?.Mode = BindingMode.TwoWay;
}
}
diff --git a/src/Controls/TableViewFilterItemsControl.xaml.cs b/src/Controls/TableViewFilterItemsControl.xaml.cs
index 834af92a..50b2c42c 100644
--- a/src/Controls/TableViewFilterItemsControl.xaml.cs
+++ b/src/Controls/TableViewFilterItemsControl.xaml.cs
@@ -16,7 +16,6 @@ namespace WinUI.TableView.Controls;
public partial class TableViewFilterItemsControl : UserControl
{
private bool _canSetState = true;
- private ICollection? _filterItems;
///
/// Initializes a new instance of the class.
@@ -93,8 +92,8 @@ internal void SetSelectAllCheckBoxState()
}
- selectAllCheckBox.IsChecked = _filterItems?.All(x => x.IsSelected) ?? false ? true
- : _filterItems?.All(x => !x.IsSelected) ?? false ? false
+ selectAllCheckBox.IsChecked = FilterItems?.All(x => x.IsSelected) ?? false ? true
+ : FilterItems?.All(x => !x.IsSelected) ?? false ? false
: null;
}
@@ -119,9 +118,9 @@ internal void SetFilterItemsState(bool isSelected)
///
private void AttachPropertyChangedHandlers()
{
- if (_filterItems?.Count > 0)
+ if (FilterItems?.Count > 0)
{
- foreach (var item in _filterItems)
+ foreach (var item in FilterItems)
{
item.PropertyChanged += OnFilterItemPropertyChanged;
}
@@ -133,9 +132,9 @@ private void AttachPropertyChangedHandlers()
///
private void DetachPropertyChangedHandlers()
{
- if (_filterItems?.Count > 0)
+ if (FilterItems?.Count > 0)
{
- foreach (var item in _filterItems)
+ foreach (var item in FilterItems)
{
item.PropertyChanged -= OnFilterItemPropertyChanged;
}
@@ -160,14 +159,14 @@ private void OnFilterItemPropertyChanged(object? sender, PropertyChangedEventArg
///
internal ICollection? FilterItems
{
- get => _filterItems;
+ get;
set
{
- if (_filterItems == value) return;
+ if (field == value) return;
DetachPropertyChangedHandlers();
- _filterItems = value;
- filterItemsList.ItemsSource = _filterItems;
+ field = value;
+ filterItemsList.ItemsSource = field;
AttachPropertyChangedHandlers();
SetSelectAllCheckBoxState();
}
diff --git a/src/ItemsSource/CollectionView.Properties.cs b/src/ItemsSource/CollectionView.Properties.cs
index 6c022501..ff75986f 100644
--- a/src/ItemsSource/CollectionView.Properties.cs
+++ b/src/ItemsSource/CollectionView.Properties.cs
@@ -13,25 +13,25 @@ partial class CollectionView
///
public IEnumerable Source
{
- get => _source;
+ get;
set
{
- if (_source == value) return;
+ if (field == value) return;
- DetachCollectionChangedHandlers(_source);
- DetachPropertyChangedHandlers(_source);
+ DetachCollectionChangedHandlers(field);
+ DetachPropertyChangedHandlers(field);
- _source = value;
+ field = value;
- AttachCollectionChangedHandlers(_source);
- AttachPropertyChangedHandlers(_source);
+ AttachCollectionChangedHandlers(field);
+ AttachPropertyChangedHandlers(field);
- CreateItemsCopy(_source);
+ CreateItemsCopy(field);
HandleSourceChanged();
OnPropertyChanged();
}
- }
+ } = new List();
///
/// Gets a value indicating whether this CollectionView can filter its items.
@@ -81,7 +81,7 @@ public object? CurrentItem
///
/// Gets a value indicating whether there are more items to load.
///
- public bool HasMoreItems => (_source as ISupportIncrementalLoading)?.HasMoreItems ?? false;
+ public bool HasMoreItems => (Source as ISupportIncrementalLoading)?.HasMoreItems ?? false;
///
/// Gets a value indicating whether the current item is after the last item in the view.
@@ -101,23 +101,23 @@ public object? CurrentItem
///
/// Gets a value indicating whether the collection is read-only.
///
- public bool IsReadOnly => _source == null || _source.IsReadOnly();
+ public bool IsReadOnly => Source == null || Source.IsReadOnly();
///
/// Gets or sets a value indicating whether live shaping is enabled.
///
public bool AllowLiveShaping
{
- get => _allowLiveShaping;
+ get;
set
{
- if (_allowLiveShaping == value) return;
+ if (field == value) return;
- _allowLiveShaping = value;
- if (_allowLiveShaping)
- AttachPropertyChangedHandlers(_source);
+ field = value;
+ if (field)
+ AttachPropertyChangedHandlers(Source);
else
- DetachPropertyChangedHandlers(_source);
+ DetachPropertyChangedHandlers(Source);
}
}
}
diff --git a/src/ItemsSource/CollectionView.cs b/src/ItemsSource/CollectionView.cs
index 18e42342..96106468 100644
--- a/src/ItemsSource/CollectionView.cs
+++ b/src/ItemsSource/CollectionView.cs
@@ -17,9 +17,7 @@ namespace WinUI.TableView;
///
internal partial class CollectionView : ICollectionView, ISupportIncrementalLoading, INotifyPropertyChanged, IComparer
{
- private IEnumerable _source = new List();
private object[] _itemsCopy = []; // In case the source is ICollection, keep a copy of the items to keep track of removed items.
- private bool _allowLiveShaping;
private readonly List _view = [];
private readonly ObservableCollection _filterDescriptions = [];
private readonly ObservableCollection _sortDescriptions = [];
@@ -171,12 +169,12 @@ private void OnSourceVectorChanged(IObservableVector sender, IVectorChan
}
DetachPropertyChangedHandlers(_itemsCopy);
- AttachPropertyChangedHandlers(_source);
+ AttachPropertyChangedHandlers(Source);
break;
}
- CreateItemsCopy(_source);
+ CreateItemsCopy(Source);
}
///
@@ -237,7 +235,7 @@ private void OnSourceCollectionChanged(object? arg1, NotifyCollectionChangedEven
}
DetachPropertyChangedHandlers(e.OldItems);
- AttachPropertyChangedHandlers(_source);
+ AttachPropertyChangedHandlers(Source);
break;
}
@@ -266,7 +264,7 @@ private void OnItemPropertyChanged(object? item, PropertyChangedEventArgs e)
}
else if (viewIndex == -1 && filterResult)
{
- var index = _source.IndexOf(item);
+ var index = Source.IndexOf(item);
HandleItemAdded(index, item);
}
}
@@ -328,7 +326,7 @@ private void HandleSourceChanged()
}
else
{
- _view.AddRange(_source.OfType());
+ _view.AddRange(Source.OfType());
}
if (SortDescriptions.Count > 0)
@@ -362,7 +360,7 @@ private void HandleFilterChanged()
var viewHash = new HashSet(_view);
var viewIndex = 0;
var i = 0;
- foreach (var item in _source)
+ foreach (var item in Source)
{
if (viewHash.Contains(item))
{
@@ -418,7 +416,7 @@ private bool HandleItemAdded(int newStartingIndex, object? newItem, int? viewInd
}
else if (FilterDescriptions.Any())
{
- if (_source == null)
+ if (Source == null)
{
HandleSourceChanged();
return false;
@@ -506,7 +504,7 @@ public void Add(object item)
{
if (IsReadOnly) throw new NotSupportedException("Collection is read-only.");
- _source.Add(item);
+ Source.Add(item);
}
///
@@ -516,7 +514,7 @@ public void Clear()
{
if (IsReadOnly) throw new NotSupportedException("Collection is read-only.");
- _source.Clear();
+ Source.Clear();
}
///
@@ -558,7 +556,7 @@ public void Insert(int index, object item)
{
if (IsReadOnly) throw new NotSupportedException("Collection is read-only.");
- _source.Insert(index, item);
+ Source.Insert(index, item);
}
///
@@ -626,7 +624,7 @@ public bool Remove(object? item)
{
if (IsReadOnly) throw new NotSupportedException("Collection is read-only.");
- _source.Remove(item);
+ Source.Remove(item);
return true;
}
@@ -661,7 +659,7 @@ IEnumerator IEnumerable.GetEnumerator()
/// An asynchronous operation that returns the result of the load operation.
public IAsyncOperation? LoadMoreItemsAsync(uint count)
{
- return (_source as ISupportIncrementalLoading)?.LoadMoreItemsAsync(count);
+ return (Source as ISupportIncrementalLoading)?.LoadMoreItemsAsync(count);
}
///
diff --git a/src/TableView.Properties.cs b/src/TableView.Properties.cs
index e0f762a8..f782956a 100644
--- a/src/TableView.Properties.cs
+++ b/src/TableView.Properties.cs
@@ -719,9 +719,9 @@ public DataTemplate? RowHeaderTemplate
///
/// Gets or sets the data template selector for the row header.
///
- public DataTemplateSelector RowHeaderTemplateSelector
+ public DataTemplateSelector? RowHeaderTemplateSelector
{
- get => (DataTemplateSelector)GetValue(RowHeaderTemplateSelectorProperty);
+ get => (DataTemplateSelector?)GetValue(RowHeaderTemplateSelectorProperty);
set => SetValue(RowHeaderTemplateSelectorProperty, value);
}
@@ -755,9 +755,9 @@ public DataTemplate? RowDetailsTemplate
///
/// Gets or sets the data template selector for the row details.
///
- public DataTemplateSelector RowDetailsTemplateSelector
+ public DataTemplateSelector? RowDetailsTemplateSelector
{
- get => (DataTemplateSelector)GetValue(RowDetailsTemplateSelectorProperty);
+ get => (DataTemplateSelector?)GetValue(RowDetailsTemplateSelectorProperty);
set => SetValue(RowDetailsTemplateSelectorProperty, value);
}
diff --git a/src/TableView.cs b/src/TableView.cs
index a640e402..77156a97 100644
--- a/src/TableView.cs
+++ b/src/TableView.cs
@@ -338,7 +338,7 @@ protected async override void OnApplyTemplate()
_headerRow = GetTemplateChild("HeaderRow") as TableViewHeaderRow;
_scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
_headerRowDefinition = GetTemplateChild("HeaderRowDefinition") as RowDefinition;
- if (_scrollViewer is not null) _scrollViewer.Loaded += OnScrollViewerLoaded;
+ _scrollViewer?.Loaded += OnScrollViewerLoaded;
if (IsLoaded)
{
@@ -359,15 +359,9 @@ private void OnScrollViewerLoaded(object sender, RoutedEventArgs e)
var xScrollBar = _scrollViewer?.FindDescendant(sb => sb.Name is "HorizontalScrollBar2");
var yScrollBar = _scrollViewer?.FindDescendant(sb => sb.Name is "VerticalScrollBar");
- if (scrollPresenter is not null)
- {
- scrollPresenter.PointerWheelChanged += OnScrollContentPresenterPointerWheelChanged;
- }
+ scrollPresenter?.PointerWheelChanged += OnScrollContentPresenterPointerWheelChanged;
- if (yScrollBar is not null)
- {
- yScrollBar.ValueChanged += (_, _) => SetValue(VerticalOffsetProperty, yScrollBar.Value);
- }
+ yScrollBar?.ValueChanged += (_, _) => SetValue(VerticalOffsetProperty, yScrollBar.Value);
xScrollBar?.SetBinding(RangeBase.ValueProperty, new Binding
{
@@ -507,8 +501,8 @@ internal void CopyToClipboardInternal(bool includeHeaders)
{
// Skip TableView copy logic when a cell editor already handles Ctrl+C.
// TextBox, PasswordBox, and RichEditBox all implement their own copy behavior.
- var focused = FocusManager.GetFocusedElement() as FrameworkElement;
- if (focused is TextBox || focused is PasswordBox || focused is RichEditBox)
+ var focused = FocusManager.GetFocusedElement(XamlRoot!) as FrameworkElement;
+ if (focused is TextBox or PasswordBox or RichEditBox)
{
return;
}
@@ -520,7 +514,7 @@ internal void CopyToClipboardInternal(bool includeHeaders)
{
return;
}
-
+
var content = GetSelectedClipboardContent(includeHeaders);
if (string.IsNullOrWhiteSpace(content))
@@ -533,7 +527,7 @@ internal void CopyToClipboardInternal(bool includeHeaders)
{
var package = new DataPackage();
package.SetText(content);
-
+
Clipboard.SetContent(package);
}
catch (Exception ex)
@@ -898,7 +892,11 @@ internal async void ExportAllToCSV()
///
/// Gets a storage file for saving the CSV.
///
- private async Task GetStorageFile()
+ private
+#if !WINDOWS
+ static
+#endif
+ async Task GetStorageFile()
{
var savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("CSV (Comma delimited)", [".csv"]);
@@ -938,10 +936,7 @@ public void ClearAllSorting()
foreach (var column in Columns.Where(c => c.SortDirection is not null))
{
- if (column is not null)
- {
- column.SortDirection = null;
- }
+ column?.SortDirection = null;
}
}
diff --git a/src/TableViewCell.cs b/src/TableViewCell.cs
index a94899b7..47a1f952 100644
--- a/src/TableViewCell.cs
+++ b/src/TableViewCell.cs
@@ -28,7 +28,6 @@ namespace WinUI.TableView;
#endif
public partial class TableViewCell : ContentControl
{
- private TableViewColumn? _column;
private ScrollViewer? _scrollViewer;
private ContentPresenter? _contentPresenter;
private Border? _selectionBorder;
@@ -614,12 +613,12 @@ internal void EnsureStyle(object? item)
///
public TableViewColumn? Column
{
- get => _column;
+ get;
internal set
{
- if (_column != value)
+ if (field != value)
{
- _column = value;
+ field = value;
OnColumnChanged();
}
}
diff --git a/src/TableViewColumnHeader.cs b/src/TableViewColumnHeader.cs
index 345190aa..e61b0efe 100644
--- a/src/TableViewColumnHeader.cs
+++ b/src/TableViewColumnHeader.cs
@@ -65,10 +65,7 @@ public TableViewColumnHeader()
///
private void OnWidthChanged(DependencyObject sender, DependencyProperty dp)
{
- if (Column is not null)
- {
- Column.ActualWidth = Width;
- }
+ Column?.ActualWidth = Width;
}
///
@@ -181,6 +178,8 @@ private void ApplyFilter()
var firstItem = selectedValues.FirstOrDefault(x => x is not null);
var firstItemType = firstItem?.GetType();
+#pragma warning disable IDE0306 // Simplify collection initialization
+#pragma warning disable IDE0028 // Simplify collection initialization
return firstItemType switch
{
Type t when t == typeof(int) => new ObjectBackedTypedSet(selectedValues),
@@ -191,6 +190,8 @@ private void ApplyFilter()
_ => [.. selectedValues],
};
+#pragma warning restore IDE0028 // Simplify collection initialization
+#pragma warning restore IDE0306 // Simplify collection initialization
}
///
@@ -230,30 +231,15 @@ protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
- if (_optionsFlyout is not null)
- {
- _optionsFlyout.Opening -= OnOptionsFlyoutOpening;
- _optionsFlyout.Closed -= OnOptionsFlyoutClosed;
- }
-
- if (_optionsButton is not null)
- {
- _optionsButton.Tapped -= OnOptionsButtonTaped;
- }
-
- if (_filterItemsMenuItem is not null)
- {
- _filterItemsMenuItem.PreviewKeyUp -= OnFilterItemsMenuItemPreviewKeyUp;
- }
-
- if (_filterItemsControl is not null)
- {
- _filterItemsControl.FilterItems = null;
- _filterItemsControl.TableView = null;
- _filterItemsControl.ColumnHeader = null;
- _filterItemsControl = null;
- }
+ _optionsFlyout?.Opening -= OnOptionsFlyoutOpening;
+ _optionsFlyout?.Closed -= OnOptionsFlyoutClosed;
+ _optionsButton?.Tapped -= OnOptionsButtonTaped;
+ _filterItemsMenuItem?.PreviewKeyUp -= OnFilterItemsMenuItemPreviewKeyUp;
+ _filterItemsControl?.FilterItems = null;
+ _filterItemsControl?.TableView = null;
+ _filterItemsControl?.ColumnHeader = null;
+ _filterItemsControl = null;
_tableView = this.FindAscendant();
_headerRow = this.FindAscendant();
_optionsButton = GetTemplateChild("OptionsButton") as Button;
@@ -271,19 +257,13 @@ protected override void OnApplyTemplate()
_optionsFlyout.Closed += OnOptionsFlyoutClosed;
_optionsButton.Tapped += OnOptionsButtonTaped;
- if (_filterItemsMenuItem is not null)
- {
- _filterItemsMenuItem.ApplyTemplate();
- _filterItemsControl = _filterItemsMenuItem.FindDescendant();
+ _filterItemsMenuItem?.ApplyTemplate();
+ _filterItemsControl = _filterItemsMenuItem?.FindDescendant();
- if (_filterItemsControl is not null)
- {
- _filterItemsControl.TableView = _tableView;
- _filterItemsControl.ColumnHeader = this;
- }
+ _filterItemsControl?.TableView = _tableView;
+ _filterItemsControl?.ColumnHeader = this;
- _filterItemsMenuItem.PreviewKeyUp += OnFilterItemsMenuItemPreviewKeyUp;
- }
+ _filterItemsMenuItem?.PreviewKeyUp += OnFilterItemsMenuItemPreviewKeyUp;
SetOptionCommands();
SetFilterButtonVisibility();
@@ -361,19 +341,13 @@ internal void OnIsFilteredChanged()
///
internal void SetFilterButtonVisibility()
{
- if (_optionsButton is not null)
- {
- _optionsButton.Visibility = CanFilter ? Visibility.Visible : Visibility.Collapsed;
- }
+ _optionsButton?.Visibility = CanFilter ? Visibility.Visible : Visibility.Collapsed;
- if (_contentPresenter is not null)
- {
- _contentPresenter.Margin = CanFilter ? new Thickness(
+ _contentPresenter?.Margin = CanFilter ? new Thickness(
Padding.Left,
Padding.Top,
Padding.Right + 8,
0) : Padding;
- }
}
///
diff --git a/src/TableViewFilterItem.cs b/src/TableViewFilterItem.cs
index 76749ede..4e3fa955 100644
--- a/src/TableViewFilterItem.cs
+++ b/src/TableViewFilterItem.cs
@@ -10,8 +10,6 @@ public partial class TableViewFilterItem : INotifyPropertyChanged
///
public event PropertyChangedEventHandler? PropertyChanged;
- private bool _isSelected;
-
///
/// Initializes a new instance of the FilterItem class.
///
@@ -32,10 +30,10 @@ public TableViewFilterItem(bool isSelected, object? value, int count = 1, bool s
///
public bool IsSelected
{
- get => _isSelected;
+ get;
set
{
- _isSelected = value;
+ field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));
}
}
diff --git a/src/TableViewHeaderRow.OptionComamnds.cs b/src/TableViewHeaderRow.OptionComamnds.cs
index 6d84a5ae..d8b5f8b7 100644
--- a/src/TableViewHeaderRow.OptionComamnds.cs
+++ b/src/TableViewHeaderRow.OptionComamnds.cs
@@ -25,15 +25,8 @@ internal void SetExportOptionsVisibility()
{
var visibility = TableView?.ShowExportOptions is true ? Visibility.Visible : Visibility.Collapsed;
- if (_exportAllMenuItem is not null)
- {
- _exportAllMenuItem.Visibility = visibility;
- }
-
- if (_exportSelectedMenuItem is not null)
- {
- _exportSelectedMenuItem.Visibility = visibility;
- }
+ _exportAllMenuItem?.Visibility = visibility;
+ _exportSelectedMenuItem?.Visibility = visibility;
}
///
diff --git a/src/TableViewHeaderRow.cs b/src/TableViewHeaderRow.cs
index 86183243..2c302ba0 100644
--- a/src/TableViewHeaderRow.cs
+++ b/src/TableViewHeaderRow.cs
@@ -42,7 +42,6 @@ public partial class TableViewHeaderRow : Control
private TranslateTransform? _columnDropIndicatorTransform;
private Image? _dragHeaderImage;
private bool _calculatingHeaderWidths;
- private DispatcherTimer? _timer;
private int _dropColumnIndex;
private bool _isValidDropTarget;
private readonly Dictionary _callbackTokens = [];
@@ -60,16 +59,9 @@ protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
- if (_selectAllButton is not null)
- {
- _selectAllButton.Tapped -= OnSelectAllButtonClicked;
- }
-
- if (_selectAllCheckBox is not null)
- {
- _selectAllCheckBox.Checked -= OnSelectAllCheckBoxChecked;
- _selectAllCheckBox.Unchecked -= OnSelectAllCheckBoxUnchecked;
- }
+ _selectAllButton?.Tapped -= OnSelectAllButtonClicked;
+ _selectAllCheckBox?.Checked -= OnSelectAllCheckBoxChecked;
+ _selectAllCheckBox?.Unchecked -= OnSelectAllCheckBoxUnchecked;
_cornerButtonPanel = GetTemplateChild("CornerButtonPanel") as Panel;
_optionsButton = GetTemplateChild("optionsButton") as Button;
@@ -88,16 +80,9 @@ protected override void OnApplyTemplate()
return;
}
- if (_selectAllButton is not null)
- {
- _selectAllButton.Tapped += OnSelectAllButtonClicked;
- }
-
- if (_selectAllCheckBox is not null)
- {
- _selectAllCheckBox.Checked += OnSelectAllCheckBoxChecked;
- _selectAllCheckBox.Unchecked += OnSelectAllCheckBoxUnchecked;
- }
+ _selectAllButton?.Tapped += OnSelectAllButtonClicked;
+ _selectAllCheckBox?.Checked += OnSelectAllCheckBoxChecked;
+ _selectAllCheckBox?.Unchecked += OnSelectAllCheckBoxUnchecked;
if (TableView.Columns is not null)
{
@@ -216,35 +201,6 @@ e.PropertyName is nameof(TableViewColumn.IsFrozen)) &&
CalculateHeaderWidths();
}
}
- else if (e.PropertyName is nameof(TableViewColumn.DesiredWidth))
- {
- if (_timer is null)
- {
- _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
- _timer.Tick += OnTimerTick;
- }
-
- _timer.Stop();
- _timer.Start();
- }
- }
-
- ///
- /// Handles the timer tick event.
- ///
- private void OnTimerTick(object? sender, object e)
- {
- if (!_calculatingHeaderWidths)
- {
- CalculateHeaderWidths();
- }
-
- if (_timer is not null)
- {
- _timer.Stop();
- _timer.Tick -= OnTimerTick;
- _timer = null;
- }
}
///
@@ -595,25 +551,13 @@ internal void ShowColumnDropIndicator(double position, RenderTargetBitmap header
x -= _columnDropIndicator.ActualWidth / 2;
_dropColumnIndex += midPoint > position ? -1 : 0;
_columnDropIndicator.Visibility = Visibility.Visible;
-
- if (_columnDropIndicatorTransform is not null)
- {
- _columnDropIndicatorTransform.X = x;
- }
-
- if (_dragHeaderImage is not null)
- {
- _dragHeaderImage.Source = headerVisuals;
- }
+ _columnDropIndicatorTransform?.X = x;
+ _dragHeaderImage?.Source = headerVisuals;
}
else
{
_isValidDropTarget = false;
-
- if (_columnDropIndicator is not null)
- {
- _columnDropIndicator.Visibility = Visibility.Collapsed;
- }
+ _columnDropIndicator?.Visibility = Visibility.Collapsed;
}
}
diff --git a/src/TableViewRow.cs b/src/TableViewRow.cs
index d403a149..3f8a4278 100644
--- a/src/TableViewRow.cs
+++ b/src/TableViewRow.cs
@@ -32,8 +32,6 @@ public partial class TableViewRow : ListViewItem
private Thickness _focusVisualMargin = new(1);
private readonly Thickness _selectionBackgroundMargin = new(4, 2, 4, 2);
private readonly Thickness _selectionIndicatorMargin = new(4, 0, 0, 0);
-
- private TableView? _tableView;
private ListViewItemPresenter? _itemPresenter;
private Border? _selectionBackground;
private bool _ensureCells = true;
@@ -147,7 +145,7 @@ protected override void OnContentChanged(object oldContent, object newContent)
}
RowPresenter?.InvalidateMeasure(); // The cells presenter does not measure every time.
- _tableView?.EnsureAlternateRowColors();
+ TableView?.EnsureAlternateRowColors();
}
///
@@ -627,13 +625,13 @@ private double GetHorizontalGridlineHeight()
///
public TableView? TableView
{
- get => _tableView;
+ get;
internal set
{
- if (_tableView != value)
+ if (field != value)
{
OnTableViewChanging();
- _tableView = value;
+ field = value;
OnTableViewChanged();
}
}
diff --git a/src/TableViewRowPresenter.cs b/src/TableViewRowPresenter.cs
index 3ea196ca..59b443a0 100644
--- a/src/TableViewRowPresenter.cs
+++ b/src/TableViewRowPresenter.cs
@@ -48,20 +48,14 @@ protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
- if (_detailsToggleButton is not null)
- {
- _detailsToggleButton.Tapped -= OnDetailsToggleButtonTapped;
- }
+ _detailsToggleButton?.Tapped -= OnDetailsToggleButtonTapped;
- if (_detailsPanel is not null)
- {
- _detailsPanel.SizeChanged -= OnDetailsPanelSizeChanged;
+ _detailsPanel?.SizeChanged -= OnDetailsPanelSizeChanged;
- if (_detailsPanelVisibilityCallbackToken is long token)
- {
- _detailsPanel.UnregisterPropertyChangedCallback(VisibilityProperty, token);
- _detailsPanelVisibilityCallbackToken = null;
- }
+ if (_detailsPanelVisibilityCallbackToken is long token)
+ {
+ _detailsPanel?.UnregisterPropertyChangedCallback(VisibilityProperty, token);
+ _detailsPanelVisibilityCallbackToken = null;
}
_rowHeader = GetTemplateChild("RowHeader") as TableViewRowHeader;
@@ -77,17 +71,10 @@ protected override void OnApplyTemplate()
_itemPresenter = this.FindAscendant();
TableViewRow = this.FindAscendant();
TableView = TableViewRow?.TableView;
+ _rowHeader?.TableView = TableView;
+ _rowHeader?.TableViewRow = TableViewRow;
- if (_rowHeader is not null)
- {
- _rowHeader.TableView = TableView;
- _rowHeader.TableViewRow = TableViewRow;
- }
-
- if (_detailsToggleButton is not null)
- {
- _detailsToggleButton.Tapped += OnDetailsToggleButtonTapped;
- }
+ _detailsToggleButton?.Tapped += OnDetailsToggleButtonTapped;
if (_detailsPanel is not null)
{
@@ -266,7 +253,7 @@ internal void ApplyDetailsPaneState(object? item)
if (TableView?.RowDetailsVisibilityMode is TableViewRowDetailsVisibilityMode.VisibleWhenExpanded &&
_detailsToggleButton is not null && TableView is not null && item is not null)
{
- var isChecked = TableView.DetailsPaneStates.TryGetValue(item, out var value) ? value.Value : false;
+ var isChecked = TableView.DetailsPaneStates.TryGetValue(item, out var value) && value.Value;
_detailsToggleButton!.IsChecked = isChecked;
ToggleDetailsPane(item, isChecked);
}
diff --git a/src/WinUI.TableView.csproj b/src/WinUI.TableView.csproj
index bcdf89da..9937dcb8 100644
--- a/src/WinUI.TableView.csproj
+++ b/src/WinUI.TableView.csproj
@@ -5,7 +5,7 @@
net9.0;
net10.0;
- 12
+ 14
enable
true
diff --git a/tests/TableViewBoundColumnTests.cs b/tests/TableViewBoundColumnTests.cs
new file mode 100644
index 00000000..b3dd8d03
--- /dev/null
+++ b/tests/TableViewBoundColumnTests.cs
@@ -0,0 +1,42 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewBoundColumnTests
+{
+ [UITestMethod]
+ public void TableViewBoundColumn_BindingAndOperationBinding_UseExpectedDefaults()
+ {
+ var binding = new Binding
+ {
+ Path = new PropertyPath(nameof(ColumnTestItem.Name)),
+ Mode = BindingMode.OneWay,
+ UpdateSourceTrigger = UpdateSourceTrigger.Default
+ };
+
+ var column = new TableViewTextColumn
+ {
+ Binding = binding
+ };
+
+ Assert.AreEqual(BindingMode.TwoWay, column.Binding.Mode);
+ Assert.AreEqual(UpdateSourceTrigger.Explicit, column.Binding.UpdateSourceTrigger);
+ Assert.AreSame(column.Binding, column.OperationContentBinding);
+ }
+
+ [UITestMethod]
+ public void TableViewBoundColumn_ClipboardContentBinding_FallsBackToBinding()
+ {
+ var column = new TableViewTextColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Name)) }
+ };
+
+ Assert.AreSame(column.Binding, column.ClipboardContentBinding);
+ Assert.AreEqual(nameof(ColumnTestItem.Name), column.ClipboardContentBinding!.Path!.Path);
+ }
+}
diff --git a/tests/TableViewCheckBoxColumnTests.cs b/tests/TableViewCheckBoxColumnTests.cs
new file mode 100644
index 00000000..1b660a80
--- /dev/null
+++ b/tests/TableViewCheckBoxColumnTests.cs
@@ -0,0 +1,52 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewCheckBoxColumnTests
+{
+ [UITestMethod]
+ public void TableViewCheckBoxColumn_UsesSingleElementAndTracksReadOnlyState()
+ {
+ var tableView = new TableView { IsReadOnly = false };
+ var column = new TableViewCheckBoxColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.IsEnabled)) }
+ };
+ column.SetOwningTableView(tableView);
+
+ var checkBox = (CheckBox)column.GenerateElement(new TableViewCell(), new ColumnTestItem());
+ var cell = new TableViewCell { Content = checkBox };
+
+ Assert.IsTrue(column.UseSingleElement);
+ Assert.IsTrue(checkBox.IsHitTestVisible);
+
+ column.IsReadOnly = true;
+ column.UpdateElementState(cell, null);
+
+ Assert.IsFalse(checkBox.IsHitTestVisible);
+ checkBox.IsChecked = true;
+ Assert.AreEqual(true, column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ Assert.ThrowsExactly(() => column.GenerateEditingElement(new TableViewCell(), null));
+ }
+
+ [UITestMethod]
+ public void TableViewCheckBoxColumn_RespectsTableViewReadOnlyState()
+ {
+ var tableView = new TableView { IsReadOnly = true };
+ var column = new TableViewCheckBoxColumn();
+ column.SetOwningTableView(tableView);
+
+ var checkBox = (CheckBox)column.GenerateElement(new TableViewCell(), null);
+
+ Assert.IsFalse(checkBox.IsHitTestVisible);
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), checkBox.Margin);
+ Assert.AreEqual(20d, checkBox.MinWidth);
+ Assert.AreEqual(20d, checkBox.MaxWidth);
+ }
+}
diff --git a/tests/TableViewColumnTestHelpers.cs b/tests/TableViewColumnTestHelpers.cs
new file mode 100644
index 00000000..4e687232
--- /dev/null
+++ b/tests/TableViewColumnTestHelpers.cs
@@ -0,0 +1,80 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Markup;
+using System;
+
+namespace WinUI.TableView.Tests;
+
+internal static class TableViewColumnTestHelpers
+{
+ public static DataTemplate CreateTemplate(string text)
+ {
+ return (DataTemplate)XamlReader.Load(
+ $"""
+
+
+
+ """);
+ }
+}
+
+internal sealed class ColumnTestColumn : TableViewColumn
+{
+ public override FrameworkElement GenerateElement(TableViewCell cell, object? dataItem) => new TextBlock();
+
+ public override FrameworkElement GenerateEditingElement(TableViewCell cell, object? dataItem) => new TextBox();
+}
+
+internal sealed class ConstantTemplateSelector(DataTemplate template) : DataTemplateSelector
+{
+ protected override DataTemplate SelectTemplateCore(object item) => template;
+}
+
+internal sealed class PrefixConverter : IValueConverter
+{
+ public object Convert(object value, Type targetType, object parameter, string language) => $"{parameter}{value}";
+
+ public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotSupportedException();
+}
+
+internal sealed class ColumnTestItem
+{
+ public string? Name { get; set; }
+
+ public string? ClipboardText { get; set; }
+
+ public ColumnTestNestedItem? Nested { get; set; }
+
+ public bool IsEnabled { get; set; }
+
+ public ColumnTestOptionItem? SelectedOption { get; set; }
+
+ public int SelectedOptionId { get; set; }
+
+ public string? SelectedOptionText { get; set; }
+
+ public DateOnly DueDate { get; set; }
+
+ public TimeOnly AppointmentTime { get; set; }
+
+ public double Amount { get; set; }
+
+ public Uri? Link { get; set; }
+
+ public object? UnknownDateLikeValue { get; set; }
+
+ public object? UnknownTimeLikeValue { get; set; }
+}
+
+internal sealed class ColumnTestNestedItem
+{
+ public string? Value { get; set; }
+}
+
+internal sealed class ColumnTestOptionItem
+{
+ public int Id { get; set; }
+
+ public string? Name { get; set; }
+}
diff --git a/tests/TableViewColumnTests.cs b/tests/TableViewColumnTests.cs
new file mode 100644
index 00000000..3933ade7
--- /dev/null
+++ b/tests/TableViewColumnTests.cs
@@ -0,0 +1,109 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewColumnTests
+{
+ [UITestMethod]
+ public void TableViewColumn_Constructor_InitializesConditionalCellStyles()
+ {
+ var column = new ColumnTestColumn();
+
+ Assert.IsNotNull(column.ConditionalCellStyles);
+ Assert.AreEqual(0, column.ConditionalCellStyles.Count);
+ }
+
+ [UITestMethod]
+ public void TableViewColumn_ContentAccessors_UseConfiguredBindings()
+ {
+ var column = new ColumnTestColumn
+ {
+ OperationContentBinding = new Binding
+ {
+ Path = new PropertyPath($"{nameof(ColumnTestItem.Nested)}.{nameof(ColumnTestNestedItem.Value)}"),
+ Converter = new PrefixConverter(),
+ ConverterParameter = "display:"
+ },
+ ClipboardContentBinding = new Binding
+ {
+ Path = new PropertyPath(nameof(ColumnTestItem.ClipboardText)),
+ Converter = new PrefixConverter(),
+ ConverterParameter = "clipboard:"
+ }
+ };
+
+ var item = new ColumnTestItem
+ {
+ Nested = new ColumnTestNestedItem { Value = "row value" },
+ ClipboardText = "copy value"
+ };
+
+ Assert.AreEqual("display:row value", column.GetCellContent(item));
+ Assert.AreEqual("clipboard:copy value", column.GetClipboardContent(item));
+ Assert.IsNull(column.GetCellContent(null));
+ Assert.IsNull(column.GetClipboardContent(null));
+ }
+
+ [UITestMethod]
+ public void TableViewColumn_ClipboardContentBinding_FallsBackToOperationContentBinding()
+ {
+ var operationBinding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Name)) };
+ var column = new ColumnTestColumn
+ {
+ OperationContentBinding = operationBinding
+ };
+
+ var item = new ColumnTestItem { Name = "fallback" };
+
+ Assert.AreSame(operationBinding, column.ClipboardContentBinding);
+ Assert.AreEqual("fallback", column.GetClipboardContent(item));
+ }
+
+ [UITestMethod]
+ public void TableViewColumn_GetCellContent_ReturnsInput_WhenNoBindingIsConfigured()
+ {
+ var column = new ColumnTestColumn();
+ var item = new ColumnTestItem { Name = "raw" };
+
+ Assert.AreSame(item, column.GetCellContent(item));
+ Assert.AreSame(item, column.GetClipboardContent(item));
+ }
+
+ [UITestMethod]
+ public void TableViewColumn_EnsureHeaderStyle_UsesTableViewStyleAndColumnOverride()
+ {
+ var tableViewStyle = new Style { TargetType = typeof(TableViewColumnHeader) };
+ var columnStyle = new Style { TargetType = typeof(TableViewColumnHeader) };
+ var tableView = new TableView { ColumnHeaderStyle = tableViewStyle };
+ var headerControl = new TableViewColumnHeader();
+ var column = new ColumnTestColumn();
+
+ column.SetOwningTableView(tableView);
+ column.HeaderControl = headerControl;
+ column.EnsureHeaderStyle();
+
+ Assert.AreSame(tableViewStyle, headerControl.Style);
+
+ column.HeaderStyle = columnStyle;
+
+ Assert.AreSame(columnStyle, headerControl.Style);
+ }
+
+ [UITestMethod]
+ public void TableViewColumn_DefaultVirtualMembers_AreNoOps()
+ {
+ var column = new ColumnTestColumn();
+ var cell = new TableViewCell();
+
+ column.RefreshElement(cell, null);
+ column.UpdateElementState(cell, null);
+ column.EndCellEditing(cell, null, TableViewEditAction.Cancel, null);
+
+ Assert.IsNull(column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ }
+}
diff --git a/tests/TableViewComboBoxColumnTests.cs b/tests/TableViewComboBoxColumnTests.cs
new file mode 100644
index 00000000..9533e741
--- /dev/null
+++ b/tests/TableViewComboBoxColumnTests.cs
@@ -0,0 +1,108 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewComboBoxColumnTests
+{
+ [UITestMethod]
+ public async Task TableViewComboBoxColumn_GeneratesDisplayAndEditingElements()
+ {
+ var options = new List
+ {
+ new() { Id = 1, Name = "One" },
+ new() { Id = 2, Name = "Two" }
+ };
+
+ var item = new ColumnTestItem
+ {
+ SelectedOption = options[1],
+ SelectedOptionId = options[1].Id,
+ SelectedOptionText = options[1].Name
+ };
+
+ var column = new TableViewComboBoxColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.SelectedOption)) },
+ DisplayMemberPath = nameof(ColumnTestOptionItem.Name),
+ SelectedValuePath = nameof(ColumnTestOptionItem.Id),
+ ItemsSource = options,
+ IsEditable = true,
+ TextBinding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.SelectedOptionText)), Mode = BindingMode.OneWay },
+ SelectedValueBinding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.SelectedOptionId)), Mode = BindingMode.OneWay }
+ };
+
+ Assert.AreEqual(BindingMode.TwoWay, column.TextBinding!.Mode);
+ Assert.AreEqual(BindingMode.TwoWay, column.SelectedValueBinding!.Mode);
+
+ var element = (TextBlock)column.GenerateElement(new TableViewCell(), item);
+ var editingElement = (ComboBox)column.GenerateEditingElement(new TableViewCell(), item);
+
+ Assert.IsNotNull(element.GetBindingExpression(FrameworkElement.DataContextProperty));
+ Assert.IsNotNull(element.GetBindingExpression(TextBlock.TextProperty));
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), element.Margin);
+
+ try
+ {
+ editingElement.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(editingElement);
+ Assert.AreSame(options, editingElement.ItemsSource);
+ Assert.AreEqual(nameof(ColumnTestOptionItem.Name), editingElement.DisplayMemberPath);
+ Assert.AreEqual(nameof(ColumnTestOptionItem.Id), editingElement.SelectedValuePath);
+ Assert.IsTrue(editingElement.IsEditable);
+ Assert.AreSame(options[1], editingElement.SelectedItem);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(editingElement);
+ }
+
+ var cell = new TableViewCell { Content = editingElement };
+ Assert.AreSame(options[1], column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ }
+
+ [UITestMethod]
+ public async Task TableViewComboBoxColumn_GeneratesDisplayElementWithoutDisplayMemberPath()
+ {
+ var item = new ColumnTestItem { SelectedOptionText = "Direct text" };
+ var column = new TableViewComboBoxColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.SelectedOptionText)) }
+ };
+
+ var element = (TextBlock)column.GenerateElement(new TableViewCell(), item);
+
+ try
+ {
+ element.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(element);
+ Assert.AreEqual("Direct text", element.Text);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(element);
+ }
+ }
+
+ [UITestMethod]
+ public void TableViewComboBoxColumn_GenerateEditingElement_DoesNotBindOptionalProperties_WhenUnset()
+ {
+ var column = new TableViewComboBoxColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.SelectedOptionText)) }
+ };
+
+ var editingElement = (ComboBox)column.GenerateEditingElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.IsNull(editingElement.GetBindingExpression(ComboBox.TextProperty));
+ Assert.IsNull(editingElement.GetBindingExpression(Selector.SelectedValueProperty));
+ Assert.AreEqual(HorizontalAlignment.Stretch, editingElement.HorizontalAlignment);
+ }
+}
diff --git a/tests/TableViewDateColumnTests.cs b/tests/TableViewDateColumnTests.cs
new file mode 100644
index 00000000..e4a83ae1
--- /dev/null
+++ b/tests/TableViewDateColumnTests.cs
@@ -0,0 +1,79 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+using WinUI.TableView.Controls;
+using WinUI.TableView.Helpers;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewDateColumnTests
+{
+ [UITestMethod]
+ public void TableViewDateColumn_GeneratesEditingElementWithConfiguredProperties()
+ {
+ var minDate = new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero);
+ var maxDate = new DateTimeOffset(2024, 12, 31, 0, 0, 0, TimeSpan.Zero);
+ var item = new ColumnTestItem { DueDate = new DateOnly(2024, 6, 15) };
+ var column = new TableViewDateColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.DueDate)) },
+ MinDate = minDate,
+ MaxDate = maxDate,
+ DateFormat = "month day",
+ IsTodayHighlighted = false,
+ IsGroupLabelVisible = false,
+ IsOutOfScopeEnabled = false,
+ DayOfWeekFormat = "{dayofweek.abbreviated(2)}"
+ };
+
+ var element = (TableViewDatePicker)column.GenerateEditingElement(new TableViewCell(), item);
+ var cell = new TableViewCell { Content = element };
+ element.SelectedDate = item.DueDate;
+
+ Assert.AreEqual(minDate, element.MinDate);
+ Assert.AreEqual(maxDate, element.MaxDate);
+ Assert.AreEqual("month day", element.DateFormat);
+ Assert.IsFalse(element.IsTodayHighlighted);
+ Assert.IsFalse(element.IsGroupLabelVisible);
+ Assert.IsFalse(element.IsOutOfScopeEnabled);
+ Assert.AreEqual("{dayofweek.abbreviated(2)}", element.DayOfWeekFormat);
+ Assert.AreEqual(TableViewLocalizedStrings.DatePickerPlaceholder, element.PlaceholderText);
+ Assert.AreEqual(typeof(DateOnly), element.SourceType);
+ Assert.AreEqual(item.DueDate, column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ }
+
+ [UITestMethod]
+ public void TableViewDateColumn_GeneratesDisplayElement_WithFormatBindings()
+ {
+ var column = new TableViewDateColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.DueDate)) },
+ DateFormat = "shortdate"
+ };
+
+ var element = (TextBlock)column.GenerateElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.IsNotNull(element.GetBindingExpression(DateTimeFormatHelper.ValueProperty));
+ Assert.IsNotNull(element.GetBindingExpression(DateTimeFormatHelper.FormatProperty));
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), element.Margin);
+ }
+
+ [UITestMethod]
+ public void TableViewDateColumn_UsesCustomPlaceholderAndDateTimeOffsetFallback()
+ {
+ var column = new TableViewDateColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.UnknownDateLikeValue)) },
+ PlaceHolderText = "Choose a date"
+ };
+
+ var element = (TableViewDatePicker)column.GenerateEditingElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.AreEqual("Choose a date", element.PlaceholderText);
+ Assert.AreEqual(typeof(DateTimeOffset), element.SourceType);
+ }
+}
diff --git a/tests/TableViewHyperlinkColumnTests.cs b/tests/TableViewHyperlinkColumnTests.cs
new file mode 100644
index 00000000..21e27527
--- /dev/null
+++ b/tests/TableViewHyperlinkColumnTests.cs
@@ -0,0 +1,73 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+using System.Threading.Tasks;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewHyperlinkColumnTests
+{
+ [UITestMethod]
+ public async Task TableViewHyperlinkColumn_GeneratesBoundHyperlink()
+ {
+ var item = new ColumnTestItem
+ {
+ Link = new Uri("https://example.com/docs"),
+ Name = "Docs"
+ };
+
+ var column = new TableViewHyperlinkColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Link)) },
+ ContentBinding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Name)) }
+ };
+
+ var element = (HyperlinkButton)column.GenerateElement(new TableViewCell(), item);
+
+ try
+ {
+ element.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(element);
+ Assert.AreEqual(item.Link, element.NavigateUri);
+ Assert.AreEqual("Docs", element.Content);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(element);
+ }
+ }
+
+ [UITestMethod]
+ public async Task TableViewHyperlinkColumn_FallsBackToBindingForContent()
+ {
+ var item = new ColumnTestItem
+ {
+ Link = new Uri("https://example.com/fallback")
+ };
+
+ var column = new TableViewHyperlinkColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Link)) }
+ };
+
+ var element = (HyperlinkButton)column.GenerateElement(new TableViewCell(), item);
+
+ try
+ {
+ element.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(element);
+ Assert.AreEqual(item.Link, element.NavigateUri);
+ Assert.AreEqual(item.Link, element.Content);
+ Assert.AreEqual(HorizontalAlignment.Stretch, element.HorizontalAlignment);
+ Assert.AreEqual(HorizontalAlignment.Left, element.HorizontalContentAlignment);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(element);
+ }
+ }
+}
diff --git a/tests/TableViewNumberColumnTests.cs b/tests/TableViewNumberColumnTests.cs
new file mode 100644
index 00000000..dfd2afec
--- /dev/null
+++ b/tests/TableViewNumberColumnTests.cs
@@ -0,0 +1,52 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System.Threading.Tasks;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewNumberColumnTests
+{
+ [UITestMethod]
+ public void TableViewNumberColumn_GeneratesNumericElements()
+ {
+ var column = new TableViewNumberColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Amount)) }
+ };
+
+ var element = (TextBlock)column.GenerateElement(new TableViewCell(), null);
+ var editingElement = (NumberBox)column.GenerateEditingElement(new TableViewCell(), null);
+ editingElement.Value = 42.5;
+
+ Assert.AreEqual(TextAlignment.Right, element.TextAlignment);
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), element.Margin);
+ Assert.AreEqual(42.5, column.PrepareCellForEdit(new TableViewCell { Content = editingElement }, new RoutedEventArgs()));
+ }
+
+ [UITestMethod]
+ public async Task TableViewNumberColumn_GeneratesBoundEditingElement()
+ {
+ var item = new ColumnTestItem { Amount = 11.25 };
+ var column = new TableViewNumberColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Amount)) }
+ };
+
+ var editingElement = (NumberBox)column.GenerateEditingElement(new TableViewCell(), item);
+
+ try
+ {
+ editingElement.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(editingElement);
+ Assert.AreEqual(11.25, editingElement.Value);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(editingElement);
+ }
+ }
+}
diff --git a/tests/TableViewTemplateColumnTests.cs b/tests/TableViewTemplateColumnTests.cs
new file mode 100644
index 00000000..933fee38
--- /dev/null
+++ b/tests/TableViewTemplateColumnTests.cs
@@ -0,0 +1,66 @@
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewTemplateColumnTests
+{
+ [UITestMethod]
+ public void TableViewTemplateColumn_UsesTemplatesForDisplayEditingAndRefresh()
+ {
+ var cellTemplate = TableViewColumnTestHelpers.CreateTemplate("display");
+ var editingTemplate = TableViewColumnTestHelpers.CreateTemplate("editing");
+ var column = new TableViewTemplateColumn
+ {
+ CellTemplate = cellTemplate,
+ EditingTemplate = editingTemplate
+ };
+
+ var displayElement = (ContentControl)column.GenerateElement(new TableViewCell(), new ColumnTestItem());
+ var editingElement = (ContentControl)column.GenerateEditingElement(new TableViewCell(), new ColumnTestItem());
+ var cell = new TableViewCell();
+
+ column.RefreshElement(cell, new ColumnTestItem());
+
+ Assert.IsFalse(column.CanSort);
+ Assert.IsFalse(column.CanFilter);
+ Assert.AreSame(cellTemplate, displayElement.ContentTemplate);
+ Assert.AreSame(editingTemplate, editingElement.ContentTemplate);
+ Assert.IsInstanceOfType(cell.Content);
+ Assert.AreSame(cellTemplate, ((ContentControl)cell.Content).ContentTemplate);
+ }
+
+ [UITestMethod]
+ public void TableViewTemplateColumn_GenerateEditingElement_FallsBackToDisplayTemplate_WhenEditingTemplateIsMissing()
+ {
+ var cellTemplate = TableViewColumnTestHelpers.CreateTemplate("display");
+ var column = new TableViewTemplateColumn
+ {
+ CellTemplate = cellTemplate
+ };
+
+ var editingElement = (ContentControl)column.GenerateEditingElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.AreSame(cellTemplate, editingElement.ContentTemplate);
+ }
+
+ [UITestMethod]
+ public void TableViewTemplateColumn_UsesTemplateSelectors()
+ {
+ var displayTemplate = TableViewColumnTestHelpers.CreateTemplate("selected-display");
+ var editingTemplate = TableViewColumnTestHelpers.CreateTemplate("selected-edit");
+ var column = new TableViewTemplateColumn
+ {
+ CellTemplateSelector = new ConstantTemplateSelector(displayTemplate),
+ EditingTemplateSelector = new ConstantTemplateSelector(editingTemplate)
+ };
+
+ var displayElement = (ContentControl)column.GenerateElement(new TableViewCell(), new ColumnTestItem());
+ var editingElement = (ContentControl)column.GenerateEditingElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.AreSame(displayTemplate, displayElement.ContentTemplate);
+ Assert.AreSame(editingTemplate, editingElement.ContentTemplate);
+ }
+}
diff --git a/tests/TableViewTextColumnTests.cs b/tests/TableViewTextColumnTests.cs
new file mode 100644
index 00000000..d2ecca0f
--- /dev/null
+++ b/tests/TableViewTextColumnTests.cs
@@ -0,0 +1,60 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System.Threading.Tasks;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewTextColumnTests
+{
+ [UITestMethod]
+ public async Task TableViewTextColumn_GeneratesBoundTextElements()
+ {
+ var item = new ColumnTestItem { Name = "Alice" };
+ var column = new TableViewTextColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.Name)) }
+ };
+
+ var element = (TextBlock)column.GenerateElement(new TableViewCell(), item);
+ var editingElement = (TextBox)column.GenerateEditingElement(new TableViewCell(), item);
+
+ try
+ {
+ element.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(element);
+ Assert.AreEqual("Alice", element.Text);
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), element.Margin);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(element);
+ }
+
+ try
+ {
+ editingElement.DataContext = item;
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(editingElement);
+ Assert.AreEqual("Alice", editingElement.Text);
+ }
+ finally
+ {
+ await UnitTestApp.Current.MainWindow.UnloadTestContentAsync(editingElement);
+ }
+
+ var cell = new TableViewCell { Content = editingElement };
+ Assert.AreEqual("Alice", column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ }
+
+ [UITestMethod]
+ public void TableViewTextColumn_PrepareCellForEdit_ReturnsNull_WhenContentIsNotTextBox()
+ {
+ var column = new TableViewTextColumn();
+ var cell = new TableViewCell { Content = new TextBlock { Text = "not editing" } };
+
+ Assert.IsNull(column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ }
+}
diff --git a/tests/TableViewTimeColumnTests.cs b/tests/TableViewTimeColumnTests.cs
new file mode 100644
index 00000000..1a6f4798
--- /dev/null
+++ b/tests/TableViewTimeColumnTests.cs
@@ -0,0 +1,68 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+using Windows.Globalization.DateTimeFormatting;
+using WinUI.TableView.Controls;
+using WinUI.TableView.Helpers;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewTimeColumnTests
+{
+ [UITestMethod]
+ public void TableViewTimeColumn_GeneratesEditingElementWithConfiguredProperties()
+ {
+ var item = new ColumnTestItem { AppointmentTime = new TimeOnly(9, 30) };
+ var column = new TableViewTimeColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.AppointmentTime)) },
+ ClockIdentifier = "24HourClock",
+ MinuteIncrement = 15
+ };
+
+ var element = (TableViewTimePicker)column.GenerateEditingElement(new TableViewCell(), item);
+ var cell = new TableViewCell { Content = element };
+ element.SelectedTime = item.AppointmentTime;
+
+ Assert.AreEqual("24HourClock", element.ClockIdentifier);
+ Assert.AreEqual(15, element.MinuteIncrement);
+ Assert.AreEqual(TableViewLocalizedStrings.TimePickerPlaceholder, element.PlaceholderText);
+ Assert.AreEqual(typeof(TimeOnly), element.SourceType);
+ Assert.AreEqual(item.AppointmentTime, column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ Assert.AreEqual(DateTimeFormatter.LongTime.Clock, new TableViewTimeColumn().ClockIdentifier);
+ }
+
+ [UITestMethod]
+ public void TableViewTimeColumn_GeneratesDisplayElement_WithFormatBindings()
+ {
+ var column = new TableViewTimeColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.AppointmentTime)) }
+ };
+
+ var element = (TextBlock)column.GenerateElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.IsNotNull(element.GetBindingExpression(DateTimeFormatHelper.ValueProperty));
+ Assert.IsNotNull(element.GetBindingExpression(DateTimeFormatHelper.FormatProperty));
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), element.Margin);
+ }
+
+ [UITestMethod]
+ public void TableViewTimeColumn_UsesCustomPlaceholderAndTimeSpanFallback()
+ {
+ var column = new TableViewTimeColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.UnknownTimeLikeValue)) },
+ PlaceholderText = "Pick a time"
+ };
+
+ var element = (TableViewTimePicker)column.GenerateEditingElement(new TableViewCell(), new ColumnTestItem());
+
+ Assert.AreEqual("Pick a time", element.PlaceholderText);
+ Assert.AreEqual(typeof(TimeSpan), element.SourceType);
+ }
+}
diff --git a/tests/TableViewToggleSwitchColumnTests.cs b/tests/TableViewToggleSwitchColumnTests.cs
new file mode 100644
index 00000000..876a4fc7
--- /dev/null
+++ b/tests/TableViewToggleSwitchColumnTests.cs
@@ -0,0 +1,54 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewToggleSwitchColumnTests
+{
+ [UITestMethod]
+ public void TableViewToggleSwitchColumn_UsesSingleElementAndTracksReadOnlyState()
+ {
+ var tableView = new TableView { IsReadOnly = false };
+ var column = new TableViewToggleSwitchColumn
+ {
+ Binding = new Binding { Path = new PropertyPath(nameof(ColumnTestItem.IsEnabled)) },
+ OnContent = "On",
+ OffContent = "Off"
+ };
+ column.SetOwningTableView(tableView);
+
+ var toggleSwitch = (ToggleSwitch)column.GenerateElement(new TableViewCell(), new ColumnTestItem());
+ var cell = new TableViewCell { Content = toggleSwitch };
+
+ Assert.IsTrue(column.UseSingleElement);
+ Assert.AreEqual("On", toggleSwitch.OnContent);
+ Assert.AreEqual("Off", toggleSwitch.OffContent);
+ Assert.IsTrue(toggleSwitch.IsHitTestVisible);
+
+ tableView.IsReadOnly = true;
+ column.UpdateElementState(cell, null);
+
+ Assert.IsFalse(toggleSwitch.IsHitTestVisible);
+ toggleSwitch.IsOn = true;
+ Assert.AreEqual(true, column.PrepareCellForEdit(cell, new RoutedEventArgs()));
+ Assert.ThrowsExactly(() => column.GenerateEditingElement(new TableViewCell(), null));
+ }
+
+ [UITestMethod]
+ public void TableViewToggleSwitchColumn_RespectsTableViewReadOnlyState()
+ {
+ var tableView = new TableView { IsReadOnly = true };
+ var column = new TableViewToggleSwitchColumn();
+ column.SetOwningTableView(tableView);
+
+ var toggleSwitch = (ToggleSwitch)column.GenerateElement(new TableViewCell(), null);
+
+ Assert.IsFalse(toggleSwitch.IsHitTestVisible);
+ Assert.AreEqual(new Thickness(12, 0, 12, 0), toggleSwitch.Margin);
+ }
+}