Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions src/Collections/DependencyObjectCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#if WINDOWS
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Windows.Foundation.Collections;

namespace WinUI.TableView.Collections;

/// <summary>
/// Provides a strongly-typed wrapper around <see cref="DependencyObjectCollection"/>
/// for collections containing <typeparamref name="T"/> items.
/// </summary>
/// <typeparam name="T">The type of items in the collection.</typeparam>
[ContentProperty(Name = nameof(Items))]
[EditorBrowsable(EditorBrowsableState.Never)]
public partial class DependencyObjectCollection<T> : DependencyObjectCollection, IList<T> where T : DependencyObject
{
/// <summary>
/// Initializes a new instance of the <see cref="DependencyObjectCollection{T}"/> class.
/// </summary>
public DependencyObjectCollection()
{
VectorChanged += OnVectorChanged;
}

/// <summary>
/// Handles changes to the underlying vector of <see cref="DependencyObject"/> items.
/// </summary>
private void OnVectorChanged(IObservableVector<DependencyObject> sender, IVectorChangedEventArgs args)
{
if (args.CollectionChange is CollectionChange.ItemInserted)
{
if (this[(int)args.Index] is not T)
{
throw new InvalidOperationException($"Only items of type {typeof(T).FullName} can be added to this collection.");
}
}
}

/// <summary>
/// Gets an <see cref="IList{T}"/> view over this collection.
/// This provides strongly-typed access to the underlying items.
/// </summary>
public IList<T> Items => this;

T IList<T>.this[int index]
{
get => (T)base[index];
set => base[index] = value;
}

int ICollection<T>.Count => Count;

bool ICollection<T>.IsReadOnly => IsReadOnly;

void ICollection<T>.Add(T item)
{
Add(item);
}

void ICollection<T>.Clear()
{
Clear();
}

bool ICollection<T>.Contains(T item)
{
return Contains(item);
}

void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
CopyTo(array as DependencyObject[], arrayIndex);
}

IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
foreach (var item in this)
{
yield return (T)item;
}
}

int IList<T>.IndexOf(T item)
{
return IndexOf(item);
}

void IList<T>.Insert(int index, T item)
{
Insert(index, item);
}

bool ICollection<T>.Remove(T item)
{
var index = IndexOf(item);

if (index >= 0)
{
RemoveAt(index);
return true;
}

return false;
}

void IList<T>.RemoveAt(int index)
{
RemoveAt(index);
}
}
#endif
23 changes: 23 additions & 0 deletions src/Columns/TableViewColumn.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
using WinUI.TableView.Extensions;
using SD = WinUI.TableView.SortDirection;

Expand All @@ -20,6 +21,14 @@ public abstract partial class TableViewColumn : DependencyObject
private bool _isFrozen;
private Func<object, object?>? _funcCompiledPropertyPath;

/// <summary>
/// Initializes a new instance of the <see cref="TableViewColumn"/> class with default conditional cell styles.
/// </summary>
public TableViewColumn()
{
SetValue(ConditionalCellStylesProperty, new TableViewConditionalCellStylesCollection());
}

/// <summary>
/// Generates a display element for the cell.
/// </summary>
Expand Down Expand Up @@ -277,6 +286,15 @@ public bool CanReorder
set => SetValue(CanReorderProperty, value);
}

/// <summary>
/// Gets or sets the collection of conditional cell styles for the column.
/// </summary>
public IList<TableViewConditionalCellStyle> ConditionalCellStyles
{
get => (IList<TableViewConditionalCellStyle>)GetValue(ConditionalCellStylesProperty);
set => SetValue(ConditionalCellStylesProperty, value);
}

internal TableViewColumnsCollection? OwningCollection { get; set; }

/// <summary>
Expand Down Expand Up @@ -511,4 +529,9 @@ private static void OnHeaderStyleChanged(DependencyObject d, DependencyPropertyC
/// Identifies the CanReorder dependency property.
/// </summary>
public static readonly DependencyProperty CanReorderProperty = DependencyProperty.Register(nameof(CanReorder), typeof(bool), typeof(TableViewColumn), new PropertyMetadata(true));

/// <summary>
/// Identifies the <see cref="ConditionalCellStyles"/> dependency property.
/// </summary>
public static readonly DependencyProperty ConditionalCellStylesProperty = DependencyProperty.Register(nameof(ConditionalCellStyles), typeof(IList<TableViewConditionalCellStyle>), typeof(TableViewColumn), new PropertyMetadata(default));
}
5 changes: 5 additions & 0 deletions src/ItemsSource/CollectionView.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,9 @@ private void OnPropertyChanged([CallerMemberName] string propertyName = null!)
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler? PropertyChanged;

/// <summary>
/// Occurs when an item's property value changes.
/// </summary>
public event PropertyChangedEventHandler? ItemPropertyChanged;
}
2 changes: 2 additions & 0 deletions src/ItemsSource/CollectionView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ private void OnSourceCollectionChanged(object? arg1, NotifyCollectionChangedEven
/// </summary>
private void OnItemPropertyChanged(object? item, PropertyChangedEventArgs e)
{
ItemPropertyChanged?.Invoke(item, e);

if (!AllowLiveShaping || item is null || string.IsNullOrEmpty(e.PropertyName))
{
return;
Expand Down
15 changes: 15 additions & 0 deletions src/TableView.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ public partial class TableView
/// Identifies the CanReorderColumns dependency property.
/// </summary>
public static readonly DependencyProperty CanReorderColumnsProperty = DependencyProperty.Register(nameof(CanReorderColumns), typeof(bool), typeof(TableView), new PropertyMetadata(true));

/// <summary>
/// Identifies the <see cref="ConditionalCellStyles"/> dependency property.
/// </summary>
public static readonly DependencyProperty ConditionalCellStylesProperty = DependencyProperty.Register(nameof(ConditionalCellStyles), typeof(IList<TableViewConditionalCellStyle>), typeof(TableView), new PropertyMetadata(default));

/// <summary>
/// Gets or sets a value indicating whether opening the column filter over header right-click is enabled.
/// </summary>
Expand Down Expand Up @@ -301,6 +307,15 @@ public TableViewCellSlot? CurrentCellSlot
set => SetValue(CurrentCellSlotProperty, value);
}

/// <summary>
/// Gets or sets the collection of conditional cell styles.
/// </summary>
public IList<TableViewConditionalCellStyle> ConditionalCellStyles
{
get => (IList<TableViewConditionalCellStyle>)GetValue(ConditionalCellStylesProperty);
set => SetValue(ConditionalCellStylesProperty, value);
}

/// <summary>
/// Gets or sets the selection start cell slot.
/// </summary>
Expand Down
23 changes: 19 additions & 4 deletions src/TableView.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.WinUI;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
Expand All @@ -8,6 +7,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
Expand All @@ -19,7 +19,6 @@
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.System;
using WinRT.Interop;
using WinUI.TableView.Extensions;
using WinUI.TableView.Helpers;

Expand Down Expand Up @@ -49,12 +48,17 @@ public TableView()

Columns = new TableViewColumnsCollection(this);
FilterHandler = new ColumnFilterHandler(this);

base.ItemsSource = _collectionView;
base.SelectionMode = SelectionMode;

SetValue(ConditionalCellStylesProperty, new TableViewConditionalCellStylesCollection());
RegisterPropertyChangedCallback(ItemsControl.ItemsSourceProperty, OnBaseItemsSourceChanged);
RegisterPropertyChangedCallback(ListViewBase.SelectionModeProperty, OnBaseSelectionModeChanged);

Loaded += OnLoaded;
SelectionChanged += TableView_SelectionChanged;
_collectionView.ItemPropertyChanged += OnItemPropertyChanged;
}

/// <summary>
Expand Down Expand Up @@ -84,6 +88,16 @@ private void TableView_SelectionChanged(object sender, SelectionChangedEventArgs
}
}

/// <summary>
/// Handles the PropertyChanged event of an item in the TableView.
/// </summary>
private void OnItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
var row = ContainerFromItem(sender) as TableViewRow;

row?.EnsureCellsStyle(default, sender);
}

/// <inheritdoc/>
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
Expand All @@ -93,6 +107,7 @@ protected override void PrepareContainerForItemOverride(DependencyObject element
{
if (element is TableViewRow row)
{
row.EnsureCellsStyle(default, item);
row.ApplyCellsSelectionState();

if (CurrentCellSlot.HasValue)
Expand Down Expand Up @@ -735,8 +750,8 @@ private async Task<StorageFile> GetStorageFile()
var savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("CSV (Comma delimited)", [".csv"]);
#if WINDOWS
var hWnd = Win32Interop.GetWindowFromWindowId(XamlRoot.ContentIslandEnvironment.AppWindowId);
InitializeWithWindow.Initialize(savePicker, hWnd);
var hWnd = Microsoft.UI.Win32Interop.GetWindowFromWindowId(XamlRoot.ContentIslandEnvironment.AppWindowId);
WinRT.Interop.InitializeWithWindow.Initialize(savePicker, hWnd);
#endif

return await savePicker.PickSaveFileAsync();
Expand Down
21 changes: 18 additions & 3 deletions src/TableViewCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Foundation;
using WinUI.TableView.Extensions;
using WinUI.TableView.Helpers;

namespace WinUI.TableView;
Expand All @@ -32,6 +32,7 @@ public partial class TableViewCell : ContentControl
private Rectangle? _v_gridLine;
private object? _uneditedValue;
private RoutedEventArgs? _editingArgs;
private IList<TableViewConditionalCellStyle>? _cellStyles;

/// <summary>
/// Initializes a new instance of the TableViewCell class.
Expand Down Expand Up @@ -84,6 +85,7 @@ protected override void OnApplyTemplate()
_v_gridLine = GetTemplateChild("VerticalGridLine") as Rectangle;

EnsureGridLines();
EnsureStyle(Row?.Content);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -111,7 +113,7 @@ protected override Size MeasureOverride(Size availableSize)
if (Column is TableViewTemplateColumn)
{
#if WINDOWS
if (element is ContentControl { ContentTemplateRoot: FrameworkElement root })
if (element is ContentControl { ContentTemplateRoot: FrameworkElement root })
#else
if (element.FindDescendant<ContentPresenter>() is { ContentTemplateRoot: FrameworkElement root })
#endif
Expand Down Expand Up @@ -368,7 +370,6 @@ internal async Task<bool> BeginCellEditing(RoutedEventArgs editingArgs)
return false;
}


/// <summary>
/// Prepares the cell for editing.
/// </summary>
Expand Down Expand Up @@ -531,6 +532,20 @@ internal void EnsureGridLines()
}
}

/// <summary>
/// Ensures the correct style is applied to the cell.
/// </summary>
/// <param name="item">The data item associated with the cell.</param>
internal void EnsureStyle(object? item)
{
_cellStyles ??= [
.. Column?.ConditionalCellStyles ?? [], // Column styles have first priority
.. TableView?.ConditionalCellStyles ?? []]; // TableView styles have second priority

Style = _cellStyles.FirstOrDefault(c => c.Predicate?.Invoke(new(Column!, item)) is true)?
.Style ?? Column?.CellStyle ?? TableView?.CellStyle;
}

/// <summary>
/// Gets a value indicating whether the cell is read-only.
/// </summary>
Expand Down
Loading