Skip to content

Commit

Permalink
Merge pull request #8 from dev
Browse files Browse the repository at this point in the history
merge dev branch into main
  • Loading branch information
w-ahmad authored May 5, 2024
2 parents a6e4ee5 + 8cd5c27 commit 3cb14af
Show file tree
Hide file tree
Showing 23 changed files with 881 additions and 609 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cd-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

- name: Build
run: |
msbuild /restore /t:Build,Pack src/WinUI.TableView/WinUI.TableView.csproj /p:Configuration=Release /p:PackageVersion=${{ steps.version.outputs.version-without-v }}.${{ github.run_number }}
msbuild /restore /t:Build,Pack src/WinUI.TableView/WinUI.TableView.csproj /p:Configuration=Release /p:PackageVersion=${{ steps.version.outputs.version-without-v }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ WinUI.TableView is a lightweight and fast data grid control made for WinUI apps.
### Features
- __Auto-generating Columns:__ Automatically generate columns based on the data source.
- __Copy row content:__ TableView allows you to copy row content, with the option to include or exclude column headers.
- __Editing:__ Modify cell content directly within the TableView by duble tapping on a cell.
- __Editing:__ Modify cell content directly within the TableView by double tapping on a cell.
![image](https://raw.githubusercontent.com/w-ahmad/WinUI.TableView/main/screenshots/Editing1.png)
![image](https://raw.githubusercontent.com/w-ahmad/WinUI.TableView/main/screenshots/Editing2.png)
- __Sorting__
![image](https://raw.githubusercontent.com/w-ahmad/WinUI.TableView/main/screenshots/Sorting.png)
- __Excel-like Column Filter:__ A key feature that allows users to filter data within columns, enhancing data exploration and analysis.
![image](https://raw.githubusercontent.com/w-ahmad/WinUI.TableView/main/screenshots/Filter.png)
- __Export fuctionality:__ Built-in export functionality to export data to CSV format. This feature can be enabled by setting the `ShowExportOptions = true`.
- __Export functionality:__ Built-in export functionality to export data to CSV format. This feature can be enabled by setting the `ShowExportOptions = true`.
![image](https://raw.githubusercontent.com/w-ahmad/WinUI.TableView/main/screenshots/Options.png)
Developers also have the flexibility to implement their own export functionality using two public methods provided:
- `GetRowsContent(bool includeHeaders, char separator)`: Retrieves the content of all rows in the table.
Expand All @@ -29,7 +29,7 @@ Developers also have the flexibility to implement their own export functionality
1. TableViewTemplateColumn

### Limitations
- Data Source Limitation: WinUI.TableView only accepts data sources that implement `System.Collections.IList`. This is because WinUI.TableView internally uses own implementaion of [AdvancedCollectionView](https://www.nuget.org/packages/CommunityToolkit.WinUI.Collections) from the [CommunityToolkit](https://github.com/CommunityToolkit/Windows), which relies on IList-based collections.
- Data Source Limitation: WinUI.TableView only accepts data sources that implements `System.Collections.IList`. This is because WinUI.TableView internally uses its own implementation of [AdvancedCollectionView](https://www.nuget.org/packages/CommunityToolkit.WinUI.Collections) from the [CommunityToolkit](https://github.com/CommunityToolkit/Windows), which relies on IList-based collections.
- Cell Selection: Cell selection is not currently supported but it's planned for the future release.

### Dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public IList Source

if (_source is INotifyCollectionChanged sourceNcc)
{
_collectionChangedListener = new (this, sourceNcc, SourceNcc_CollectionChanged);
_collectionChangedListener = new(this, sourceNcc, SourceNcc_CollectionChanged);
}

HandleSourceChanged();
Expand Down Expand Up @@ -391,7 +391,7 @@ int IComparer<object>.Compare(object? x, object? y)
object? cy;

if (!string.IsNullOrEmpty(sd.PropertyName) &&
_sortProperties.TryGetValue(sd.PropertyName, out (PropertyInfo, object?)[]? pis))
_sortProperties.TryGetValue(sd.PropertyName, out var pis))
{
cx = x.GetValue(pis);
cy = y.GetValue(pis);
Expand Down Expand Up @@ -671,7 +671,7 @@ private bool HandleItemAdded(int newStartingIndex, object? newItem, int? viewInd
return false;
}

var newViewIndex = _view.Count;
var newViewIndex = newStartingIndex;

if (_sortDescriptions.Any())
{
Expand All @@ -689,18 +689,7 @@ private bool HandleItemAdded(int newStartingIndex, object? newItem, int? viewInd
HandleSourceChanged();
return false;
}
if (viewIndex.HasValue)
{
newViewIndex = viewIndex.Value;
}
else
{
newViewIndex = _view.Take(newStartingIndex).Count();
}
}
else
{
newViewIndex = newStartingIndex;
newViewIndex = viewIndex ?? _view.Take(newStartingIndex).Count();
}

_view.Insert(newViewIndex, newItem!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace WinUI.TableView.Converters;

public class BoolToVisibilityConverter : IValueConverter
internal class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
Expand Down
2 changes: 1 addition & 1 deletion src/WinUI.TableView/Extensions/ObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal static class ObjectExtensions
{
var parts = path.Split('.');
pis = new (PropertyInfo, object?)[parts.Length];
for (int i = 0; i < parts.Length; i++)
for (var i = 0; i < parts.Length; i++)
{
var part = parts[i];
var index = default(object?);
Expand Down
95 changes: 91 additions & 4 deletions src/WinUI.TableView/TableView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ public TableView()
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (GetTemplateChild("ScrollViewer") is not ScrollViewer scrollViewer)
{
return;
}

Canvas.SetZIndex(ItemsPanelRoot, -1);

Expand Down Expand Up @@ -107,7 +109,7 @@ private string GetRowsContent(IEnumerable<object> items, bool includeHeaders, ch
foreach (var column in Columns.OfType<TableViewBoundColumn>())
{
var property = column.Binding.Path.Path;
if (!properties.TryGetValue(property, out (PropertyInfo, object?)[]? pis))
if (!properties.TryGetValue(property, out var pis))
{
stringBuilder.Append($"{item.GetValue(type, property, out pis)}{separator}");
properties.Add(property, pis);
Expand Down Expand Up @@ -357,16 +359,65 @@ private static void OnAutoGenerateColumnsChanged(DependencyObject d, DependencyP
}
}

private static void OnCanSortColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TableView tableView && e.NewValue is false)
{
tableView.ClearSorting();
}
}

private static void OnCanFilterColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TableView tableView && e.NewValue is false)
{
tableView.ClearFilters();
}
}

internal void ClearSorting()
{
CollectionView.SortDescriptions.Clear();

foreach (var header in Columns.Select(x => x.HeaderControl))
{
if (header is not null)
{
header.SortDirection = null;
}
}
}

internal void ClearFilters()
{
ActiveFilters.Clear();
CollectionView.RefreshFilter();

foreach (var header in Columns.Select(x => x.HeaderControl))
{
if (header is not null)
{
header.IsFiltered = false;
}
}
}

public IAdvancedCollectionView CollectionView { get; private set; } = new AdvancedCollectionView();

internal IDictionary<string, Predicate<object>> ActiveFilters { get; } = new Dictionary<string, Predicate<object>>();

public TableViewColumnsColection Columns
public TableViewColumnsCollection Columns
{
get => (TableViewColumnsColection)GetValue(ColumnsProperty);
get => (TableViewColumnsCollection)GetValue(ColumnsProperty);
private set => SetValue(ColumnsProperty, value);
}

public double HeaderRowHeight
{
get => (double)GetValue(HeaderRowHeightProperty);
set => SetValue(HeaderRowHeightProperty, value);
}

public double RowHeight
{
get => (double)GetValue(RowHeightProperty);
Expand Down Expand Up @@ -397,12 +448,48 @@ public bool AutoGenerateColumns
set => SetValue(AutoGenerateColumnsProperty, value);
}

public bool IsReadOnly
{
get => (bool)GetValue(IsReadOnlyProperty);
set => SetValue(IsReadOnlyProperty, value);
}

public bool ShowOptionsButton
{
get => (bool)GetValue(ShowOptionsButtonProperty);
set => SetValue(ShowOptionsButtonProperty, value);
}

public bool CanResizeColumns
{
get => (bool)GetValue(CanResizeColumnsProperty);
set => SetValue(CanResizeColumnsProperty, value);
}

public bool CanSortColumns
{
get => (bool)GetValue(CanSortColumnsProperty);
set => SetValue(CanSortColumnsProperty, value);
}

public bool CanFilterColumns
{
get => (bool)GetValue(CanFilterColumnsProperty);
set => SetValue(CanFilterColumnsProperty, value);
}

public static readonly new DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(IList), typeof(TableView), new PropertyMetadata(null, OnItemsSourceChanged));
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(nameof(Columns), typeof(TableViewColumnsColection), typeof(TableView), new PropertyMetadata(null));
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(nameof(Columns), typeof(TableViewColumnsCollection), typeof(TableView), new PropertyMetadata(null));
public static readonly DependencyProperty HeaderRowHeightProperty = DependencyProperty.Register(nameof(HeaderRowHeight), typeof(double), typeof(TableView), new PropertyMetadata(48d));
public static readonly DependencyProperty RowHeightProperty = DependencyProperty.Register(nameof(RowHeight), typeof(double), typeof(TableView), new PropertyMetadata(40d));
public static readonly DependencyProperty RowMaxHeightProperty = DependencyProperty.Register(nameof(RowMaxHeight), typeof(double), typeof(TableView), new PropertyMetadata(double.PositiveInfinity));
public static readonly DependencyProperty ShowExportOptionsProperty = DependencyProperty.Register(nameof(ShowExportOptions), typeof(bool), typeof(TableView), new PropertyMetadata(false));
public static readonly DependencyProperty AutoGenerateColumnsProperty = DependencyProperty.Register(nameof(AutoGenerateColumns), typeof(bool), typeof(TableView), new PropertyMetadata(true, OnAutoGenerateColumnsChanged));
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(TableView), new PropertyMetadata(false));
public static readonly DependencyProperty ShowOptionsButtonProperty = DependencyProperty.Register(nameof(ShowOptionsButton), typeof(bool), typeof(TableView), new PropertyMetadata(true));
public static readonly DependencyProperty CanResizeColumnsProperty = DependencyProperty.Register(nameof(CanResizeColumns), typeof(bool), typeof(TableView), new PropertyMetadata(true));
public static readonly DependencyProperty CanSortColumnsProperty = DependencyProperty.Register(nameof(CanSortColumns), typeof(bool), typeof(TableView), new PropertyMetadata(true, OnCanSortColumnsChanged));
public static readonly DependencyProperty CanFilterColumnsProperty = DependencyProperty.Register(nameof(CanFilterColumns), typeof(bool), typeof(TableView), new PropertyMetadata(true, OnCanFilterColumnsChanged));

public event EventHandler<TableViewAutoGeneratingColumnEventArgs>? AutoGeneratingColumn;
public event EventHandler<TableViewExportRowsContentEventArgs>? ExportAllRowsContent;
Expand Down
39 changes: 24 additions & 15 deletions src/WinUI.TableView/TableViewCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ namespace WinUI.TableView;

public class TableViewCell : ContentControl
{
private TableViewRow? _tableViewRow;
private TableViewColumn? _column;
private Lazy<FrameworkElement> _element = null!;
private Lazy<FrameworkElement> _editingElement = null!;

Expand All @@ -26,7 +24,7 @@ public TableViewCell()

protected override void OnDoubleTapped(DoubleTappedRoutedEventArgs e)
{
if (_column is { IsReadOnly: false })
if (!IsReadOnly)
{
PrepareForEdit();
}
Expand All @@ -36,22 +34,20 @@ protected override void OnKeyDown(KeyRoutedEventArgs e)
{
base.OnKeyDown(e);

_tableViewRow ??= this.FindAscendant<TableViewRow>();

if (e.Key is VirtualKey.Tab or VirtualKey.Enter &&
_tableViewRow is not null &&
Row is not null &&
!VisualTreeHelper.GetOpenPopupsForXamlRoot(XamlRoot).Any())
{
var shiftKey = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift);
var isShiftKeyDown = shiftKey is CoreVirtualKeyStates.Down or (CoreVirtualKeyStates.Down | CoreVirtualKeyStates.Locked);

if (isShiftKeyDown)
{
_tableViewRow.SelectPreviousCell(this);
Row.SelectPreviousCell(this);
}
else
{
_tableViewRow.SelectNextCell(this);
Row.SelectNextCell(this);
}
}
else if (e.Key == VirtualKey.Escape)
Expand Down Expand Up @@ -91,7 +87,7 @@ protected override async void OnLostFocus(RoutedEventArgs e)

private void SetElement()
{
if (_column is TableViewTemplateColumn templateColumn)
if (Column is TableViewTemplateColumn templateColumn)
{
ContentTemplate = templateColumn.CellTemplate;
}
Expand All @@ -103,11 +99,11 @@ private void SetElement()

private void SetEditingElement()
{
if (_column is TableViewTemplateColumn templateColumn)
if (Column is TableViewTemplateColumn templateColumn)
{
ContentTemplate = templateColumn.EditingTemplate ?? templateColumn.CellTemplate;
}
else if (_column is not null)
else if (Column is not null)
{
Content = _editingElement.Value;
}
Expand All @@ -117,20 +113,33 @@ private static void OnColumnChanged(DependencyObject d, DependencyPropertyChange
{
if (d is TableViewCell cell && e.NewValue is TableViewColumn column)
{
cell._column = column;
cell._element = new Lazy<FrameworkElement>(column.GenerateElement());
cell._editingElement = new Lazy<FrameworkElement>(column.GenerateEditingElement());
cell.SetElement();
}
}

public bool IsReadOnly => _column is TableViewTemplateColumn { EditingTemplate: null } || _column is { IsReadOnly: true };
public bool IsReadOnly => TableView.IsReadOnly || Column is TableViewTemplateColumn { EditingTemplate: null } or { IsReadOnly: true };

public TableViewColumn Column
{
get { return (TableViewColumn)GetValue(ColumnProperty); }
set { SetValue(ColumnProperty, value); }
get => (TableViewColumn)GetValue(ColumnProperty);
set => SetValue(ColumnProperty, value);
}

public TableViewRow Row
{
get => (TableViewRow)GetValue(TableViewRowProperty);
set => SetValue(TableViewRowProperty, value);
}

public TableView TableView
{
get => (TableView)GetValue(TableViewProperty);
set => SetValue(TableViewProperty, value);
}

public static readonly DependencyProperty ColumnProperty = DependencyProperty.Register(nameof(Column), typeof(TableViewColumn), typeof(TableViewCell), new PropertyMetadata(default, OnColumnChanged));
public static readonly DependencyProperty TableViewRowProperty = DependencyProperty.Register(nameof(Row), typeof(TableViewRow), typeof(TableViewCell), new PropertyMetadata(default));
public static readonly DependencyProperty TableViewProperty = DependencyProperty.Register(nameof(TableView), typeof(TableView), typeof(TableViewCell), new PropertyMetadata(default));
}
7 changes: 4 additions & 3 deletions src/WinUI.TableView/TableViewColumnHeader.FilterItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ public partial class TableViewColumnHeader
private class FilterItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private bool isSelected;

private bool _isSelected;
private readonly OptionsFlyoutViewModel _optionsFlyoutViewModel;

public FilterItem(bool isSelected, object value, OptionsFlyoutViewModel optionsFlyoutViewModel)
Expand All @@ -20,10 +21,10 @@ public FilterItem(bool isSelected, object value, OptionsFlyoutViewModel optionsF

public bool IsSelected
{
get => isSelected;
get => _isSelected;
set
{
isSelected = value;
_isSelected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));

_optionsFlyoutViewModel?.SetSelectAllCheckBoxState();
Expand Down
Loading

0 comments on commit 3cb14af

Please sign in to comment.