Skip to content

Commit 2ff6378

Browse files
committed
Add support IEnumerable data sources
1 parent 3c763bb commit 2ff6378

File tree

8 files changed

+476
-22
lines changed

8 files changed

+476
-22
lines changed

src/ColumnFilterHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Diagnostics.CodeAnalysis;
45
using System.Linq;
@@ -40,7 +41,7 @@ public virtual IList<TableViewFilterItem> GetFilterItems(TableViewColumn column,
4041
}));
4142
}
4243

43-
collectionView.Source = column.TableView.ItemsSource;
44+
collectionView.Source = (column.TableView.ItemsSource as IEnumerable) ?? Enumerable.Empty<object>();
4445

4546
var items = _tableView.ShowFilterItemsCount ?
4647
GetFilterItemsWithCount(column, searchText, collectionView) :

src/Extensions/CollectionExtensions.cs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System;
1+
using Microsoft.UI.Xaml.Data;
2+
using System;
3+
using System.Collections;
24
using System.Collections.Generic;
35
using System.Linq;
46

@@ -38,4 +40,83 @@ public static void RemoveWhere<T>(this ICollection<T> collection, Predicate<T> p
3840
collection.Remove(item);
3941
}
4042
}
43+
44+
/// <summary>
45+
/// Gets the index of the first occurrence of an item in the enumerable.
46+
/// </summary>
47+
/// <param name="enumerable">The enumerable to search.</param>
48+
/// <param name="item">The item to find.</param>
49+
/// <returns>The index of the item, or -1 if not found.</returns>
50+
public static int IndexOf(this IEnumerable enumerable, object? item)
51+
{
52+
if (enumerable is ICollection collection)
53+
return collection.IndexOf(item);
54+
55+
if (enumerable is ICollectionView collectionView)
56+
return collectionView.IndexOf(item);
57+
58+
59+
var index = 0;
60+
foreach (var element in enumerable)
61+
{
62+
if (Equals(element, item))
63+
return index;
64+
65+
index++;
66+
}
67+
68+
return -1;
69+
}
70+
71+
/// <summary>
72+
/// Gets a value indicating whether the enumerable is read-only.
73+
/// </summary>
74+
/// <param name="enumerable">The enumerable to check.</param>
75+
/// <returns></returns>
76+
public static bool IsReadOnly(this IEnumerable enumerable)
77+
{
78+
if (enumerable is IList list)
79+
return list.IsReadOnly;
80+
81+
if (enumerable is ICollectionView collectionView)
82+
return collectionView.IsReadOnly;
83+
84+
return true;
85+
}
86+
87+
public static void Add(this IEnumerable enumerable, object? item)
88+
{
89+
if (enumerable is ICollection collection)
90+
collection.Add(item);
91+
92+
if (enumerable is ICollectionView collectionView)
93+
collectionView.Add(item);
94+
}
95+
96+
public static void Insert(this IEnumerable enumerable, int index, object? item)
97+
{
98+
if (enumerable is ICollection collection)
99+
collection.Insert(index, item);
100+
101+
if (enumerable is ICollectionView collectionView)
102+
collectionView.Insert(index, item);
103+
}
104+
105+
public static void Remove(this IEnumerable enumerable, object? item)
106+
{
107+
if (enumerable is ICollection collection)
108+
collection.Remove(item);
109+
110+
if (enumerable is ICollectionView collectionView)
111+
collectionView.Remove(item);
112+
}
113+
114+
public static void Clear(this IEnumerable enumerable)
115+
{
116+
if (enumerable is ICollection collection)
117+
collection.Clear();
118+
119+
if (enumerable is ICollectionView collectionView)
120+
collectionView.Clear();
121+
}
41122
}

src/Extensions/ObjectExtensions.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ private static bool TryCreateGenericIndexerExpression(Type type, ParameterExpres
400400
var listType = list.GetType();
401401
Type? itemType = null;
402402
var isICustomTypeProvider = false;
403+
var isWinRTObject = false;
403404

404405
// If it's a generic enumerable, get the generic type.
405406

@@ -410,11 +411,14 @@ private static bool TryCreateGenericIndexerExpression(Type type, ParameterExpres
410411
if (itemType != null)
411412
{
412413
isICustomTypeProvider = typeof(ICustomTypeProvider).IsAssignableFrom(itemType);
414+
#if WINDOWS
415+
isWinRTObject = typeof(WinRT.IInspectable).IsAssignableFrom(itemType);
416+
#endif
413417
}
414418

415419
// Bare IEnumerables mean that result type will be object. In that case, try to get something more interesting.
416420
// Or, if the itemType implements ICustomTypeProvider, try to retrieve the custom type from one of the object instances.
417-
if (itemType == null || itemType == typeof(object) || isICustomTypeProvider)
421+
if (itemType == null || itemType == typeof(object) || isICustomTypeProvider || isWinRTObject)
418422
{
419423
// No type was located yet. Does the list have anything in it?
420424
Type? firstItemType = null;

src/ItemsSource/CollectionView.Properties.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Collections.Specialized;
55
using Windows.Foundation.Collections;
6+
using WinUI.TableView.Extensions;
67

78
namespace WinUI.TableView;
89

@@ -11,7 +12,7 @@ partial class CollectionView
1112
/// <summary>
1213
/// Gets or sets the source collection.
1314
/// </summary>
14-
public IList Source
15+
public IEnumerable Source
1516
{
1617
get => _source;
1718
set
@@ -103,7 +104,7 @@ public object? CurrentItem
103104
/// <summary>
104105
/// Gets a value indicating whether the collection is read-only.
105106
/// </summary>
106-
public bool IsReadOnly => _source == null || _source.IsReadOnly;
107+
public bool IsReadOnly => _source == null || _source.IsReadOnly();
107108

108109
/// <summary>
109110
/// Gets or sets a value indicating whether live shaping is enabled.

src/ItemsSource/CollectionView.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq;
99
using Windows.Foundation;
1010
using Windows.Foundation.Collections;
11+
using WinUI.TableView.Extensions;
1112
using WinUI.TableView.Helpers;
1213

1314
namespace WinUI.TableView;
@@ -17,7 +18,7 @@ namespace WinUI.TableView;
1718
/// </summary>
1819
internal partial class CollectionView : ICollectionView, ISupportIncrementalLoading, INotifyPropertyChanged, IComparer<object?>
1920
{
20-
private IList _source = default!;
21+
private IEnumerable _source = new List<object>();
2122
private bool _allowLiveShaping;
2223
private readonly List<object?> _view = [];
2324
private readonly ObservableCollection<FilterDescription> _filterDescriptions = [];
@@ -29,7 +30,7 @@ internal partial class CollectionView : ICollectionView, ISupportIncrementalLoad
2930
/// </summary>
3031
/// <param name="source">The source collection.</param>
3132
/// <param name="liveShapingEnabled">Indicates whether live shaping is enabled.</param>
32-
public CollectionView(IList? source = null, bool liveShapingEnabled = true)
33+
public CollectionView(IEnumerable? source = null, bool liveShapingEnabled = true)
3334
{
3435
_filterDescriptions.CollectionChanged += OnFilterDescriptionsCollectionChanged;
3536
_sortDescriptions.CollectionChanged += OnSortDescriptionsCollectionChanged;
@@ -242,7 +243,7 @@ private void HandleSourceChanged()
242243
/// </summary>
243244
private void HandleFilterChanged()
244245
{
245-
if (FilterDescriptions.Any())
246+
if (FilterDescriptions.Count > 0)
246247
{
247248
for (var index = 0; index < _view.Count; index++)
248249
{
@@ -259,19 +260,21 @@ private void HandleFilterChanged()
259260

260261
var viewHash = new HashSet<object?>(_view);
261262
var viewIndex = 0;
262-
for (var index = 0; index < _source.Count; index++)
263+
var i = 0;
264+
foreach (var item in _source)
263265
{
264-
var item = _source[index]!;
265266
if (viewHash.Contains(item))
266267
{
267268
viewIndex++;
268269
continue;
269270
}
270271

271-
if (HandleItemAdded(index, item, viewIndex))
272+
if (HandleItemAdded(i, item, viewIndex))
272273
{
273274
viewIndex++;
274275
}
276+
277+
i++;
275278
}
276279
}
277280

src/TableView.Properties.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using Microsoft.UI.Xaml.Data;
55
using Microsoft.UI.Xaml.Media;
66
using System;
7-
using System.Collections;
87
using System.Collections.Generic;
98
using System.Linq;
109
using System.Threading.Tasks;
@@ -19,7 +18,7 @@ public partial class TableView
1918
/// <summary>
2019
/// Identifies the ItemsSource dependency property.
2120
/// </summary>
22-
public static readonly new DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(IList), typeof(TableView), new PropertyMetadata(null, OnItemsSourceChanged));
21+
public static readonly new DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(TableView), new PropertyMetadata(null, OnItemsSourceChanged));
2322

2423
/// <summary>
2524
/// Identifies the SelectionMode dependency property.
@@ -437,9 +436,9 @@ public double RowMinHeight
437436
/// <summary>
438437
/// Gets or sets an object source used to generate the content of the TableView.
439438
/// </summary>
440-
public new IList? ItemsSource
439+
public new object? ItemsSource
441440
{
442-
get => (IList?)GetValue(ItemsSourceProperty);
441+
get => GetValue(ItemsSourceProperty);
443442
set => SetValue(ItemsSourceProperty, value);
444443
}
445444

src/TableView.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,9 @@ private string GetHeadersContent(char separator, int minColumn, int maxColumn)
573573
/// </summary>
574574
private void GenerateColumns()
575575
{
576-
var dataType = ItemsSource?.GetItemType();
576+
if (ItemsSource is not IEnumerable source) return;
577+
578+
var dataType = source?.GetItemType();
577579
if (dataType is null || dataType.IsPrimitive())
578580
{
579581
var columnArgs = GenerateColumn(dataType, null, "", dataType?.IsInheritedFromIComparable() is true);
@@ -666,15 +668,15 @@ private static TableViewBoundColumn GetTableViewColumnFromType(string? propertyN
666668
private void ItemsSourceChanged(DependencyPropertyChangedEventArgs e)
667669
{
668670
using var defer = _collectionView.DeferRefresh();
669-
_collectionView.Source = null!;
671+
_collectionView.Source = null!;
670672

671-
if (e.NewValue is IList source)
672-
{
673-
EnsureAutoColumns();
673+
if (e.NewValue is IEnumerable source)
674+
{
675+
EnsureAutoColumns();
674676

675-
_collectionView.Source = source;
676-
}
677+
_collectionView.Source = source;
677678
}
679+
}
678680

679681
/// <summary>
680682
/// Ensures that columns are automatically generated based on the current state of the control.

0 commit comments

Comments
 (0)