diff --git a/src/EventArgs/TableViewColumnPropertyChangedEventArgs.cs b/src/EventArgs/TableViewColumnPropertyChangedEventArgs.cs
index 5bb40ad..ffe3594 100644
--- a/src/EventArgs/TableViewColumnPropertyChangedEventArgs.cs
+++ b/src/EventArgs/TableViewColumnPropertyChangedEventArgs.cs
@@ -5,7 +5,7 @@ namespace WinUI.TableView;
///
/// Provides data for the ColumnPropertyChanged event.
///
-internal class TableViewColumnPropertyChangedEventArgs : EventArgs
+public class TableViewColumnPropertyChangedEventArgs : EventArgs
{
///
/// Initializes a new instance of the TableViewColumnPropertyChanged class.
diff --git a/src/ITableViewColumnsCollection.cs b/src/ITableViewColumnsCollection.cs
new file mode 100644
index 0000000..2d6ffc0
--- /dev/null
+++ b/src/ITableViewColumnsCollection.cs
@@ -0,0 +1,41 @@
+using Microsoft.UI.Xaml;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+
+namespace WinUI.TableView;
+
+///
+/// Represents a collection of columns in a , providing functionality to manage and interact with the columns.
+///
+/// This interface extends to provide standard list operations for objects. It also implements to notify subscribers of
+/// changes to the collection, such as additions or removals.
+public interface ITableViewColumnsCollection : IList, INotifyCollectionChanged
+{
+ ///
+ /// Occurs when a property of a column changes.
+ ///
+ ///
+ /// This event is triggered to notify subscribers about changes to column properties, such as width, visibility, or other attributes.
+ /// Handlers can use the parameter to access details about the specific property that changed.
+ ///
+ event EventHandler? ColumnPropertyChanged;
+
+ ///
+ /// Gets the list of visible s.
+ ///
+ ///
+ /// The result is a list of columns that are currently visible in the table view, meaning their is set to .
+ /// The result is also ordered by the property, allowing for a consistent display order of the columns.
+ ///
+ IList VisibleColumns { get; }
+
+ ///
+ /// Gets or sets the associated with the collection.
+ ///
+ ///
+ /// This property allows access to the that owns this collection of columns.
+ ///
+ TableView? TableView { get; }
+}
diff --git a/src/TableView.Properties.cs b/src/TableView.Properties.cs
index 83785e2..5184baf 100644
--- a/src/TableView.Properties.cs
+++ b/src/TableView.Properties.cs
@@ -265,7 +265,7 @@ public TableViewCellSlot? CurrentCellSlot
///
/// Gets the collection of columns in the TableView.
///
- public TableViewColumnsCollection Columns { get; } = [];
+ public ITableViewColumnsCollection Columns { get; }
///
/// Gets or sets the height of the header row.
diff --git a/src/TableView.cs b/src/TableView.cs
index a82f928..155a572 100644
--- a/src/TableView.cs
+++ b/src/TableView.cs
@@ -48,7 +48,7 @@ public TableView()
{
DefaultStyleKey = typeof(TableView);
- Columns.TableView = this;
+ Columns = new TableViewColumnsCollection(this);
FilterHandler = new ColumnFilterHandler(this);
base.ItemsSource = _collectionView;
base.SelectionMode = SelectionMode;
diff --git a/src/TableViewColumnsCollection.cs b/src/TableViewColumnsCollection.cs
index a9c83d2..3f96200 100644
--- a/src/TableViewColumnsCollection.cs
+++ b/src/TableViewColumnsCollection.cs
@@ -1,70 +1,162 @@
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.Collections.Specialized;
-using System.ComponentModel;
using System.Linq;
+using Windows.Foundation.Collections;
namespace WinUI.TableView;
///
-/// Represents a collection of columns in a TableView.
+/// Represents a collection of objects used in a .
///
-public partial class TableViewColumnsCollection : ObservableCollection
+/// This collection provides functionality for managing columns in a , including adding,
+/// removing, and tracking changes to column properties. It supports notifications for collection changes and column
+/// property changes, enabling dynamic updates to the .
+public partial class TableViewColumnsCollection : DependencyObjectCollection, ITableViewColumnsCollection
{
+ private TableViewColumn[] _itemsCopy = []; // To keep a copy of the items to keep track of removed items
+ ///
+ public event EventHandler? ColumnPropertyChanged;
+ ///
+ public event NotifyCollectionChangedEventHandler? CollectionChanged;
+
///
- /// Occurs when a property of a column in the collection changes.
+ /// The constructor for the class.
///
- internal event EventHandler? ColumnPropertyChanged;
+ ///
+ /// The that owns this collection.
+ ///
+ public TableViewColumnsCollection(TableView tableView)
+ {
+ TableView = tableView ?? throw new ArgumentNullException(nameof(tableView));
+ VectorChanged += OnVectorChanged;
+ }
///
- /// Gets the list of visible columns in the collection.
+ /// Handles changes to the underlying vector of items.
///
- internal IList VisibleColumns =>
- [.. Items.Where(x => x.Visibility == Visibility.Visible)
- .OrderBy(x => x.Order ?? 0)];
-
- ///
- protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
+ private void OnVectorChanged(IObservableVector sender, IVectorChangedEventArgs args)
{
- base.OnCollectionChanged(e);
+ var index = (int)args.Index;
- if (e.NewItems != null)
+ switch (args.CollectionChange)
{
- foreach (var column in e.NewItems.OfType())
- {
- column.SetOwningCollection(this);
- column.SetOwningTableView(TableView!);
- }
+ case CollectionChange.ItemInserted:
+ if (args.Index < Count)
+ {
+ var column = (TableViewColumn)sender[index];
+ column.SetOwningCollection(this);
+ column.SetOwningTableView(((ITableViewColumnsCollection)this).TableView!);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, column, (int)args.Index));
+ }
+ break;
+ case CollectionChange.ItemRemoved:
+ if (args.Index < _itemsCopy.Length)
+ {
+ var column = _itemsCopy[index];
+ column.SetOwningCollection(null!);
+ column.SetOwningTableView(null!);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, column, (int)args.Index));
+ }
+ break;
+ case CollectionChange.Reset:
+ foreach (var item in _itemsCopy)
+ {
+ item.SetOwningCollection(null!);
+ item.SetOwningTableView(null!);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+ break;
}
- if (e.OldItems != null)
- {
- foreach (var column in e.OldItems.OfType())
- {
- column.SetOwningCollection(null!);
- column.SetOwningTableView(null!);
- }
- }
+ _itemsCopy = new TableViewColumn[Count];
+ CopyTo(_itemsCopy, 0);
}
///
/// Handles the property changed event for a column.
///
- /// The column that changed.
- /// The name of the property that changed.
internal void HandleColumnPropertyChanged(TableViewColumn column, string propertyName)
{
- if (Items.Contains(column))
+ if (Contains(column) && this is ITableViewColumnsCollection d)
{
var index = IndexOf(column);
ColumnPropertyChanged?.Invoke(this, new TableViewColumnPropertyChangedEventArgs(column, propertyName, index));
}
}
- ///
- /// Gets or sets the TableView associated with the collection.
- ///
- public TableView? TableView { get; internal set; }
-}
+ ///
+ public TableView? TableView { get; }
+
+ ///
+ public IList VisibleColumns => [.. this.OfType()
+ .Where(x => x.Visibility == Visibility.Visible)
+ .OrderBy(x => x.Order ?? 0)];
+
+ TableViewColumn IList.this[int index]
+ {
+ get => (TableViewColumn)base[index];
+ set => base[index] = value;
+ }
+
+ int ICollection.Count => Count;
+
+ bool ICollection.IsReadOnly => IsReadOnly;
+
+ void ICollection.Add(TableViewColumn item)
+ {
+ Add(item);
+ }
+
+ void ICollection.Clear()
+ {
+ Clear();
+ }
+
+ bool ICollection.Contains(TableViewColumn item)
+ {
+ return Contains(item);
+ }
+
+ void ICollection.CopyTo(TableViewColumn[] array, int arrayIndex)
+ {
+ CopyTo(array, arrayIndex);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ foreach (var item in this)
+ {
+ yield return (TableViewColumn)item;
+ }
+ }
+
+ int IList.IndexOf(TableViewColumn item)
+ {
+ return IndexOf(item);
+ }
+
+ void IList.Insert(int index, TableViewColumn item)
+ {
+ Insert(index, item);
+ }
+
+ bool ICollection.Remove(TableViewColumn item)
+ {
+ var index = IndexOf(item);
+
+ if (index >= 0)
+ {
+ RemoveAt(index);
+ return true;
+ }
+
+ return false;
+ }
+
+ void IList.RemoveAt(int index)
+ {
+ RemoveAt(index);
+ }
+}
\ No newline at end of file
diff --git a/tests/TableViewColumnsCollectionTests.cs b/tests/TableViewColumnsCollectionTests.cs
new file mode 100644
index 0000000..2b1dc6b
--- /dev/null
+++ b/tests/TableViewColumnsCollectionTests.cs
@@ -0,0 +1,189 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System;
+using System.Collections.Specialized;
+
+namespace WinUI.TableView.Tests;
+
+[TestClass]
+public class TableViewColumnsCollectionTests
+{
+ [UITestMethod]
+ public void Constructor_ShouldInitializeTableViewProperty()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ Assert.AreEqual(tableView, collection.TableView);
+ }
+
+ [UITestMethod]
+ public void Add_ShouldRaiseCollectionChangedEvent()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ var column = new TableViewTextColumn();
+
+ var eventRaised = false;
+ collection.CollectionChanged += (s, e) => eventRaised = true;
+
+ collection.Add(column);
+
+ Assert.IsTrue(eventRaised);
+ }
+
+ [UITestMethod]
+ public void Remove_ShouldRaiseCollectionChangedEvent()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ var column = new TableViewTextColumn();
+
+ collection.Add(column);
+
+ var eventRaised = false;
+ collection.CollectionChanged += (s, e) => eventRaised = true;
+
+ collection.Remove(column);
+
+ Assert.IsTrue(eventRaised);
+ }
+
+ [UITestMethod]
+ public void VisibleColumns_ShouldReturnOnlyVisibleColumns()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+
+ var visibleColumn = new TableViewTextColumn { Visibility = Visibility.Visible };
+ var hiddenColumn = new TableViewTextColumn { Visibility = Visibility.Collapsed };
+
+ collection.Add(visibleColumn);
+ collection.Add(hiddenColumn);
+
+ var visibleColumns = collection.VisibleColumns;
+
+ Assert.AreEqual(1, visibleColumns.Count);
+ Assert.AreEqual(visibleColumn, visibleColumns[0]);
+ }
+
+ [UITestMethod]
+ public void HandleColumnPropertyChanged_ShouldRaiseColumnPropertyChangedEvent()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ var column = new TableViewTextColumn();
+
+ collection.Add(column);
+
+ var eventRaised = false;
+ collection.ColumnPropertyChanged += (s, e) => eventRaised = true;
+
+ collection.HandleColumnPropertyChanged(column, "TestProperty");
+
+ Assert.IsTrue(eventRaised);
+ }
+
+ [UITestMethod]
+ public void HandleColumnPropertyChanged_ShouldNotRaiseEvent_ForInvalidColumn()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ var column = new TableViewTextColumn();
+
+ var eventRaised = false;
+ collection.ColumnPropertyChanged += (s, e) => eventRaised = true;
+
+ collection.HandleColumnPropertyChanged(column, "TestProperty");
+
+ Assert.IsFalse(eventRaised);
+ }
+
+ [UITestMethod]
+ public void ResetCollection_ShouldRaiseCollectionChangedEvent()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ var column1 = new TableViewTextColumn();
+ var column2 = new TableViewTextColumn();
+
+ collection.Add(column1);
+ collection.Add(column2);
+
+ var eventRaised = false;
+ collection.CollectionChanged += (s, e) =>
+ {
+ if (e.Action == NotifyCollectionChangedAction.Reset)
+ {
+ eventRaised = true;
+ }
+ };
+
+ collection.Clear();
+
+ Assert.IsTrue(eventRaised);
+ }
+
+
+ [UITestMethod]
+ public void VisibleColumns_ShouldReturnColumnsInCorrectOrder()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+
+ var column1 = new TableViewTextColumn { Header = "column1", Visibility = Visibility.Visible, Order = 1 };
+ var column2 = new TableViewTextColumn { Header = "column2", Visibility = Visibility.Visible, Order = 2 };
+ var column3 = new TableViewTextColumn { Header = "column3", Visibility = Visibility.Visible, Order = 1 };
+
+ collection.Add(column1);
+ collection.Add(column2);
+ collection.Add(column3);
+
+ var visibleColumns = collection.VisibleColumns;
+
+ Assert.AreEqual(column1, visibleColumns[0]);
+ Assert.AreEqual(column3, visibleColumns[1]);
+ Assert.AreEqual(column2, visibleColumns[2]);
+ }
+
+ [UITestMethod]
+ public void AddDuplicateColumns_ShouldHandleCorrectly()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+ var column = new TableViewTextColumn();
+
+ collection.Add(column);
+ collection.Add(column);
+
+ Assert.AreEqual(2, collection.Count);
+ }
+
+ [UITestMethod]
+ public void ColumnVisibilityChange_ShouldUpdateVisibleColumns()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+
+ var column = new TableViewTextColumn { Visibility = Visibility.Visible };
+ collection.Add(column);
+
+ Assert.AreEqual(1, collection.VisibleColumns.Count);
+
+ column.Visibility = Visibility.Collapsed;
+
+ Assert.AreEqual(0, collection.VisibleColumns.Count);
+ }
+
+ [UITestMethod]
+ public void Add_ShouldThrowException_ForInvalidObjectType()
+ {
+ var tableView = new TableView();
+ var collection = new TableViewColumnsCollection(tableView);
+
+ var invalidObject = new TextBox();
+
+ Assert.ThrowsExactly(() => collection.Add(invalidObject));
+ }
+}