From 1cda9944e222840b636cec3df56cb08ff48c3498 Mon Sep 17 00:00:00 2001 From: Alessio Dell Aquila Date: Thu, 6 Jun 2024 13:37:20 +0200 Subject: [PATCH 1/5] [DataGrid] Add OnCellClick and allow restricting selection to checkboxes --- ...crosoft.FluentUI.AspNetCore.Components.xml | 24 ++++++++++++++--- .../DataGrid/Examples/DataGridManual.razor | 12 ++++----- .../Examples/DataGridMultiSelect.razor | 8 +++++- .../Examples/DataGridTemplateColumns2.razor | 2 +- .../DataGrid/Columns/SelectColumn.cs | 6 +++++ .../Components/DataGrid/FluentDataGrid.razor | 6 ++--- .../DataGrid/FluentDataGrid.razor.cs | 6 +++++ .../DataGrid/FluentDataGridCell.razor | 4 ++- .../DataGrid/FluentDataGridCell.razor.cs | 27 ++++++++++++++++++- .../DataGrid/FluentDataGridRow.razor.cs | 18 ++++++++----- 10 files changed, 91 insertions(+), 22 deletions(-) diff --git a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml index d3567040e0..69f8899895 100644 --- a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml +++ b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml @@ -1386,6 +1386,11 @@ Gets or sets the content to be rendered for each row in the table. + + + Gets or sets whether the selection of rows is restricted to the checkbox cells (true) or if the whole row can be clicked to toggled the selection of rows (false). + + Gets or sets whether the [All] checkbox is disabled (not clickable). @@ -1657,6 +1662,11 @@ Gets or sets a callback when a row is clicked. + + + Gets or sets a callback when a cell is clicked. + + Gets or sets a callback when a row is double-clicked. @@ -1752,7 +1762,12 @@ Gets or sets the cell type. See . - + + + Gets or sets the column of the cell. + + + Gets or sets the column index of the cell. This will be applied to the css grid-column-index value applied to the cell. @@ -1773,6 +1788,9 @@ Gets or sets the owning component + + + Gets or sets the reference to the item that holds this row's values. @@ -6312,7 +6330,7 @@ - Defines the vertical spacing between the NavGroup and adjecent items. + Defines the vertical spacing between the NavGroup and adjacent items. Needs to be a valid CSS value. @@ -6324,7 +6342,7 @@ Allows for specific markup and styling to be applied for the group title - When using this, the containded s and s need to be placed in a ChildContent tag. + When using this, the contained s and s need to be placed in a ChildContent tag. When specifying both Title and TitleTemplate, both will be rendered. diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor index 66de4b2cb2..ec7bc4c56b 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor @@ -1,14 +1,14 @@  - Column 1 - Column 2 + Column 1 + Column 2 - 1.1 - 1.2 + 1.1 + 1.2 - 2.1 - 2.2 + 2.1 + 2.2 \ No newline at end of file diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor index ca78863f01..b577bc4e8f 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor @@ -4,6 +4,9 @@ + @if (UseSelectedItems) @@ -11,9 +14,10 @@ @* Sample using SelectedItems *@
Using SelectedItems
- + @@ -33,6 +37,7 @@ else SelectedItems = People.Where(p => p.Selected); + bool RestrictToCheckbox = false; record Person(int PersonId, string Name, DateOnly BirthDate) { diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridTemplateColumns2.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridTemplateColumns2.razor index f9b8bcce8e..e90ca77d52 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridTemplateColumns2.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridTemplateColumns2.razor @@ -37,6 +37,6 @@ private void HandleCellFocus(FluentDataGridCell cell) { - DemoLogger.WriteLine($"Cell focused: {cell.GridColumn}"); + DemoLogger.WriteLine($"Cell focused: {cell.ColumnIndex}"); } } diff --git a/src/Core/Components/DataGrid/Columns/SelectColumn.cs b/src/Core/Components/DataGrid/Columns/SelectColumn.cs index f0171e5c1a..5881490a9f 100644 --- a/src/Core/Components/DataGrid/Columns/SelectColumn.cs +++ b/src/Core/Components/DataGrid/Columns/SelectColumn.cs @@ -38,6 +38,12 @@ public SelectColumn() [Parameter] public RenderFragment ChildContent { get; set; } + /// + /// Gets or sets whether the selection of rows is restricted to the checkbox cells (true) or if the whole row can be clicked to toggled the selection of rows (false). + /// + [Parameter] + public bool RestrictToCheckbox { get; set; } = false; + /// /// Gets or sets whether the [All] checkbox is disabled (not clickable). /// diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor b/src/Core/Components/DataGrid/FluentDataGrid.razor index 2021c63008..5ff3ec2b81 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor @@ -98,7 +98,7 @@ string? tooltip = col.Tooltip ? @col.RawCellContent(item) : null; - + @((RenderFragment)(__builder => col.CellContent(__builder, item))) } @@ -114,7 +114,7 @@ { var col = _columns[colIndex]; - + @((RenderFragment)(__builder => col.RenderPlaceholderContent(__builder, placeholderContext))) } @@ -133,7 +133,7 @@ else col.ShowSortIcon = false; - + @col.HeaderContent @if (col == _displayOptionsForColumn) { diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs index 39ded8dce9..2508eb8e4c 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs @@ -130,6 +130,12 @@ public partial class FluentDataGrid : FluentComponentBase, IHandleEve [Parameter] public EventCallback> OnRowClick { get; set; } + /// + /// Gets or sets a callback when a cell is clicked. + /// + [Parameter] + public EventCallback> OnCellClick { get; set; } + /// /// Gets or sets a callback when a row is double-clicked. /// diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor b/src/Core/Components/DataGrid/FluentDataGridCell.razor index 5e05d90a24..c84ae8b33c 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor @@ -3,9 +3,11 @@ @typeparam TGridItem @ChildContent diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs index 2cf610e50e..56cecbb0fc 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs @@ -24,12 +24,18 @@ public partial class FluentDataGridCell : FluentComponentBase [Parameter] public DataGridCellType? CellType { get; set; } = DataGridCellType.Default; + /// + /// Gets or sets the column of the cell. + /// + [Parameter] + public ColumnBase? Column { get; set; } + /// /// Gets or sets the column index of the cell. /// This will be applied to the css grid-column-index value applied to the cell. /// [Parameter] - public int GridColumn { get; set; } + public int ColumnIndex { get; set; } /// /// Gets or sets the content to be rendered inside the component. @@ -61,4 +67,23 @@ protected override void OnInitialized() public void Dispose() => Owner.Unregister(this); + /// + internal async Task HandleOnCellClickAsync(string cellId) + { + if (Owner.Cells.TryGetValue(cellId, out var cell)) + { + if (GridContext.Grid.OnCellClick.HasDelegate) + { + await GridContext.Grid.OnCellClick.InvokeAsync(cell); + } + + if (cell != null && cell.CellType == DataGridCellType.Default) + { + if (Column is SelectColumn selColumn) + { + await selColumn.AddOrRemoveSelectedItemAsync(Item); + } + } + } + } } diff --git a/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs b/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs index 7954c4e983..556d8be2cc 100644 --- a/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs @@ -13,7 +13,7 @@ namespace Microsoft.FluentUI.AspNetCore.Components; public partial class FluentDataGridRow : FluentComponentBase, IHandleEvent, IDisposable { internal string RowId { get; set; } = string.Empty; - private readonly Dictionary> cells = []; + internal Dictionary> Cells { get; set; } = []; /// /// Gets or sets the reference to the item that holds this row's values. @@ -80,18 +80,18 @@ internal void Register(FluentDataGridCell cell) { cell.CellId = $"c{Owner.GetNextCellId()}"; - cells.Add(cell.CellId, cell); + Cells.Add(cell.CellId, cell); } internal void Unregister(FluentDataGridCell cell) { - cells.Remove(cell.CellId!); + Cells.Remove(cell.CellId!); } private async Task HandleOnCellFocusAsync(DataGridCellFocusEventArgs args) { var cellId = args.CellId; - if (cells.TryGetValue(cellId!, out var cell)) + if (Cells.TryGetValue(cellId!, out var cell)) { if (cell != null && cell.CellType == DataGridCellType.Default) { @@ -114,7 +114,10 @@ internal async Task HandleOnRowClickAsync(string rowId) { foreach (var selColumn in Owner.Grid.SelectColumns) { - await selColumn.AddOrRemoveSelectedItemAsync(Item); + if (!selColumn.RestrictToCheckbox) + { + await selColumn.AddOrRemoveSelectedItemAsync(Item); + } } } } @@ -144,7 +147,10 @@ internal async Task HandleOnRowKeyDownAsync(string rowId, KeyboardEventArgs e) { foreach (var selColumn in Owner.Grid.SelectColumns) { - await selColumn.AddOrRemoveSelectedItemAsync(Item); + if (!selColumn.RestrictToCheckbox) + { + await selColumn.AddOrRemoveSelectedItemAsync(Item); + } } } } From 2aab4f9a8a898e72d084d0b51acfd48994307807 Mon Sep 17 00:00:00 2001 From: Alessio Dell Aquila Date: Thu, 6 Jun 2024 14:02:36 +0200 Subject: [PATCH 2/5] Revert renaming GridColumn to ColumnIndex --- .../Pages/DataGrid/Examples/DataGridManual.razor | 12 ++++++------ .../DataGrid/Examples/DataGridMultiSelect.razor | 2 +- .../DataGrid/Examples/DataGridTemplateColumns2.razor | 2 +- src/Core/Components/DataGrid/FluentDataGrid.razor | 6 +++--- .../Components/DataGrid/FluentDataGridCell.razor | 2 +- .../Components/DataGrid/FluentDataGridCell.razor.cs | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor index ec7bc4c56b..66de4b2cb2 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridManual.razor @@ -1,14 +1,14 @@  - Column 1 - Column 2 + Column 1 + Column 2 - 1.1 - 1.2 + 1.1 + 1.2 - 2.1 - 2.2 + 2.1 + 2.2 \ No newline at end of file diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor index b577bc4e8f..a37460ebda 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor @@ -14,7 +14,7 @@ @* Sample using SelectedItems *@
Using SelectedItems
- + cell) { - DemoLogger.WriteLine($"Cell focused: {cell.ColumnIndex}"); + DemoLogger.WriteLine($"Cell focused: {cell.GridColumn}"); } } diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor b/src/Core/Components/DataGrid/FluentDataGrid.razor index 5ff3ec2b81..5b29024cac 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor @@ -98,7 +98,7 @@ string? tooltip = col.Tooltip ? @col.RawCellContent(item) : null; - + @((RenderFragment)(__builder => col.CellContent(__builder, item))) } @@ -114,7 +114,7 @@ { var col = _columns[colIndex]; - + @((RenderFragment)(__builder => col.RenderPlaceholderContent(__builder, placeholderContext))) } @@ -133,7 +133,7 @@ else col.ShowSortIcon = false; - + @col.HeaderContent @if (col == _displayOptionsForColumn) { diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor b/src/Core/Components/DataGrid/FluentDataGridCell.razor index c84ae8b33c..29ff44cf87 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor @@ -3,7 +3,7 @@ @typeparam TGridItem : FluentComponentBase /// This will be applied to the css grid-column-index value applied to the cell. ///
[Parameter] - public int ColumnIndex { get; set; } + public int GridColumn { get; set; } /// /// Gets or sets the content to be rendered inside the component. From 42830495ce59b39725d53569c3bcfed5ce5b58ba Mon Sep 17 00:00:00 2001 From: Alessio Dell Aquila Date: Thu, 6 Jun 2024 16:26:56 +0200 Subject: [PATCH 3/5] [DataGrid] Fix requested changes --- ...crosoft.FluentUI.AspNetCore.Components.xml | 10 ++---- .../DataGrid/Columns/SelectColumn.cs | 1 + .../Components/DataGrid/FluentDataGrid.razor | 12 +++---- .../DataGrid/FluentDataGrid.razor.cs | 20 +++++------ .../DataGrid/FluentDataGridCell.razor | 4 +-- .../DataGrid/FluentDataGridCell.razor.cs | 35 ++++++++++--------- .../DataGrid/FluentDataGridRow.razor.cs | 4 +-- 7 files changed, 42 insertions(+), 44 deletions(-) diff --git a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml index 69f8899895..2c6bebfb13 100644 --- a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml +++ b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml @@ -1389,6 +1389,7 @@ Gets or sets whether the selection of rows is restricted to the checkbox cells (true) or if the whole row can be clicked to toggled the selection of rows (false). + ⚠ Setting this to true will stop the from being invoked, when a cell in this column is clicked. @@ -1762,12 +1763,7 @@ Gets or sets the cell type. See . - - - Gets or sets the column of the cell. - - - + Gets or sets the column index of the cell. This will be applied to the css grid-column-index value applied to the cell. @@ -1788,7 +1784,7 @@ Gets or sets the owning component - + diff --git a/src/Core/Components/DataGrid/Columns/SelectColumn.cs b/src/Core/Components/DataGrid/Columns/SelectColumn.cs index 5881490a9f..29fddb01af 100644 --- a/src/Core/Components/DataGrid/Columns/SelectColumn.cs +++ b/src/Core/Components/DataGrid/Columns/SelectColumn.cs @@ -40,6 +40,7 @@ public SelectColumn() /// /// Gets or sets whether the selection of rows is restricted to the checkbox cells (true) or if the whole row can be clicked to toggled the selection of rows (false). + /// ⚠ Setting this to true will stop the from being invoked, when a cell in this column is clicked. /// [Parameter] public bool RestrictToCheckbox { get; set; } = false; diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor b/src/Core/Components/DataGrid/FluentDataGrid.razor index 5b29024cac..c894561fc2 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor @@ -92,9 +92,9 @@ var rowStyle = RowStyle?.Invoke(item) ?? null; Loading = false; - @for (var colIndex = 0; colIndex < _columns.Count; colIndex++) + @for (var colIndex = 0; colIndex < Columns.Count; colIndex++) { - var col = _columns[colIndex]; + var col = Columns[colIndex]; string? tooltip = col.Tooltip ? @col.RawCellContent(item) : null; @@ -110,9 +110,9 @@ string? _rowsDataSize = $"height: {ItemSize}px"; - @for (var colIndex = 0; colIndex < _columns.Count; colIndex++) + @for (var colIndex = 0; colIndex < Columns.Count; colIndex++) { - var col = _columns[colIndex]; + var col = Columns[colIndex]; @((RenderFragment)(__builder => col.RenderPlaceholderContent(__builder, placeholderContext))) @@ -124,9 +124,9 @@ private void RenderColumnHeaders(RenderTreeBuilder __builder) { - @for (var colIndex = 0; colIndex < _columns.Count; colIndex++) + @for (var colIndex = 0; colIndex < Columns.Count; colIndex++) { - var col = _columns[colIndex]; + var col = Columns[colIndex]; string CellId = Identifier.NewId(); if (_sortByColumn == col) col.ShowSortIcon = true; diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs index 2508eb8e4c..ed51111f77 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs @@ -181,7 +181,7 @@ public partial class FluentDataGrid : FluentComponentBase, IHandleEve /// /// Gets the first (optional) SelectColumn /// - internal IEnumerable> SelectColumns => _columns.Where(col => col is SelectColumn).Cast< SelectColumn>(); + internal IEnumerable> SelectColumns => Columns.Where(col => col is SelectColumn).Cast< SelectColumn>(); private ElementReference? _gridReference; private Virtualize<(int, TGridItem)>? _virtualizeComponent; @@ -193,7 +193,7 @@ public partial class FluentDataGrid : FluentComponentBase, IHandleEve // We cascade the InternalGridContext to descendants, which in turn call it to add themselves to _columns // This happens on every render so that the column list can be updated dynamically private readonly InternalGridContext _internalGridContext; - private readonly List> _columns; + internal readonly List> Columns; private bool _collectingColumns; // Columns might re-render themselves arbitrarily. We only want to capture them at a defined time. // Tracking state for options and sorting @@ -235,7 +235,7 @@ public partial class FluentDataGrid : FluentComponentBase, IHandleEve [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DataGridRowFocusEventArgs))] public FluentDataGrid() { - _columns = []; + Columns = []; _internalGridContext = new(this); _currentPageItemsChanged = new(EventCallback.Factory.Create(this, RefreshDataCoreAsync)); _renderColumnHeaders = RenderColumnHeaders; @@ -285,7 +285,7 @@ protected override Task OnParametersSetAsync() // We don't want to trigger the first data load until we've collected the initial set of columns, // because they might perform some action like setting the default sort order, so it would be wasteful // to have to re-query immediately - return (_columns.Count > 0 && mustRefreshData) ? RefreshDataCoreAsync() : Task.CompletedTask; + return (Columns.Count > 0 && mustRefreshData) ? RefreshDataCoreAsync() : Task.CompletedTask; } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -315,7 +315,7 @@ internal void AddColumn(ColumnBase column, SortDirection? initialSort { if (_collectingColumns) { - _columns.Add(column); + Columns.Add(column); if (isDefaultSortColumn && _sortByColumn is null && initialSortDirection.HasValue) { @@ -328,23 +328,23 @@ internal void AddColumn(ColumnBase column, SortDirection? initialSort private void StartCollectingColumns() { - _columns.Clear(); + Columns.Clear(); _collectingColumns = true; } private void FinishCollectingColumns() { _collectingColumns = false; - _manualGrid = _columns.Count == 0; + _manualGrid = Columns.Count == 0; - if (!string.IsNullOrWhiteSpace(GridTemplateColumns) && _columns.Where(x => x is not SelectColumn).Any(x => !string.IsNullOrWhiteSpace(x.Width))) + if (!string.IsNullOrWhiteSpace(GridTemplateColumns) && Columns.Where(x => x is not SelectColumn).Any(x => !string.IsNullOrWhiteSpace(x.Width))) { throw new Exception("You can use either the 'GridTemplateColumns' parameter on the grid or the 'Width' property at the column level, not both."); } - if (string.IsNullOrWhiteSpace(_internalGridTemplateColumns) && _columns.Any(x => !string.IsNullOrWhiteSpace(x.Width))) + if (string.IsNullOrWhiteSpace(_internalGridTemplateColumns) && Columns.Any(x => !string.IsNullOrWhiteSpace(x.Width))) { - _internalGridTemplateColumns = string.Join(" ", _columns.Select(x => x.Width ?? "1fr")); + _internalGridTemplateColumns = string.Join(" ", Columns.Select(x => x.Width ?? "1fr")); } if (ResizableColumns) diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor b/src/Core/Components/DataGrid/FluentDataGridCell.razor index 29ff44cf87..18a9c9a815 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor @@ -6,8 +6,8 @@ grid-column=@GridColumn class="@Class" style="@StyleValue" - @onclick="@(e => HandleOnCellClickAsync(CellId))" - @onclick:stopPropagation="@(Column is SelectColumn)" + @onclick="@HandleOnCellClickAsync" + @onclick:stopPropagation="StopClickPropagation()" @attributes="AdditionalAttributes"> @ChildContent diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs index 60b4180887..6f2c1c18c7 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs @@ -3,6 +3,7 @@ // ------------------------------------------------------------------------ using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure; using Microsoft.FluentUI.AspNetCore.Components.Utilities; @@ -24,12 +25,6 @@ public partial class FluentDataGridCell : FluentComponentBase [Parameter] public DataGridCellType? CellType { get; set; } = DataGridCellType.Default; - /// - /// Gets or sets the column of the cell. - /// - [Parameter] - public ColumnBase? Column { get; set; } - /// /// Gets or sets the column index of the cell. /// This will be applied to the css grid-column-index value applied to the cell. @@ -67,22 +62,28 @@ protected override void OnInitialized() public void Dispose() => Owner.Unregister(this); + private bool StopClickPropagation() + { + var selColumn = Owner.Owner.Grid.SelectColumns.FirstOrDefault(); + + return selColumn != null && selColumn.RestrictToCheckbox is true && Owner.Owner.Grid.Columns.IndexOf(selColumn) == GridColumn - 1; + } + /// - internal async Task HandleOnCellClickAsync(string cellId) + internal async Task HandleOnCellClickAsync(MouseEventArgs args) { - if (Owner.Cells.TryGetValue(cellId, out var cell)) + if (GridContext.Grid.OnCellClick.HasDelegate) { - if (GridContext.Grid.OnCellClick.HasDelegate) - { - await GridContext.Grid.OnCellClick.InvokeAsync(cell); - } + await GridContext.Grid.OnCellClick.InvokeAsync(this); + } + + if (CellType == DataGridCellType.Default) + { + var selColumn = Owner.Owner.Grid.SelectColumns.FirstOrDefault(); - if (cell != null && cell.CellType == DataGridCellType.Default) + if (selColumn != null && selColumn.RestrictToCheckbox is true && Owner.Owner.Grid.Columns.IndexOf(selColumn) == GridColumn - 1) { - if (Column is SelectColumn selColumn) - { - await selColumn.AddOrRemoveSelectedItemAsync(Item); - } + await selColumn.AddOrRemoveSelectedItemAsync(Item); } } } diff --git a/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs b/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs index 556d8be2cc..b2856d5007 100644 --- a/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridRow.razor.cs @@ -13,7 +13,7 @@ namespace Microsoft.FluentUI.AspNetCore.Components; public partial class FluentDataGridRow : FluentComponentBase, IHandleEvent, IDisposable { internal string RowId { get; set; } = string.Empty; - internal Dictionary> Cells { get; set; } = []; + internal Dictionary> Cells { get; } = []; /// /// Gets or sets the reference to the item that holds this row's values. @@ -56,7 +56,7 @@ public partial class FluentDataGridRow : FluentComponentBase, IHandle /// Gets or sets the owning component /// [CascadingParameter] - private InternalGridContext Owner { get; set; } = default!; + internal InternalGridContext Owner { get; set; } = default!; protected string? ClassValue => new CssBuilder(Class) .AddClass("hover", when: Owner.Grid.ShowHover) From 2d0d7696d030e4869a7e215a80999c0859c39f12 Mon Sep 17 00:00:00 2001 From: Alessio Dell Aquila Date: Thu, 6 Jun 2024 17:11:16 +0200 Subject: [PATCH 4/5] [DataGrid] Added tests for RestrictToCheckbox --- ...crosoft.FluentUI.AspNetCore.Components.xml | 2 +- .../Components/DataGrid/FluentDataGrid.razor | 6 +- .../DataGrid/FluentDataGridCell.razor.cs | 3 +- .../FluentDataGridColumSelectTests.razor | 96 +++++++++++++++++++ 4 files changed, 101 insertions(+), 6 deletions(-) diff --git a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml index 2c6bebfb13..aabdf71ac5 100644 --- a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml +++ b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml @@ -1784,7 +1784,7 @@ Gets or sets the owning component - + diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor b/src/Core/Components/DataGrid/FluentDataGrid.razor index c894561fc2..74d3d6a92b 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor @@ -98,7 +98,7 @@ string? tooltip = col.Tooltip ? @col.RawCellContent(item) : null; - + @((RenderFragment)(__builder => col.CellContent(__builder, item))) } @@ -114,7 +114,7 @@ { var col = Columns[colIndex]; - + @((RenderFragment)(__builder => col.RenderPlaceholderContent(__builder, placeholderContext))) } @@ -133,7 +133,7 @@ else col.ShowSortIcon = false; - + @col.HeaderContent @if (col == _displayOptionsForColumn) { diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs index 6f2c1c18c7..8945b20bc6 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs @@ -3,7 +3,6 @@ // ------------------------------------------------------------------------ using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure; using Microsoft.FluentUI.AspNetCore.Components.Utilities; @@ -70,7 +69,7 @@ private bool StopClickPropagation() } /// - internal async Task HandleOnCellClickAsync(MouseEventArgs args) + internal async Task HandleOnCellClickAsync() { if (GridContext.Grid.OnCellClick.HasDelegate) { diff --git a/tests/Core/DataGrid/FluentDataGridColumSelectTests.razor b/tests/Core/DataGrid/FluentDataGridColumSelectTests.razor index d0acb17bc3..d6295373e5 100644 --- a/tests/Core/DataGrid/FluentDataGridColumSelectTests.razor +++ b/tests/Core/DataGrid/FluentDataGridColumSelectTests.razor @@ -318,6 +318,88 @@ cut.Verify(); } + [Fact] + public async Task FluentDataGrid_ColumSelect_SingleSelect_SelectedItems_RestrictToCheckbox() + { + IEnumerable SelectedItems = Array.Empty(); + + // Arrange + var cut = Render( + @ + + + + ); + + // Pre-Assert + Assert.Empty(cut.FindAll("svg[row-selected]")); + Assert.Empty(SelectedItems); + + // Act - Click Row 0 Cell 1 + await ClickOnCellAsync(cut, row: 0, cell: 1); + Assert.Empty(cut.FindAll("svg[row-selected]")); + Assert.Empty(SelectedItems); + + // Act - Click and select Row 0 Cell 0 + await ClickOnCellAsync(cut, row: 0, cell: 0); + Assert.Single(cut.FindAll("svg[row-selected]")); + Assert.Single(SelectedItems); + + // Act - Click Row 1 Cell 1 + await ClickOnCellAsync(cut, row: 1, cell: 1); + Assert.Single(cut.FindAll("svg[row-selected]")); + Assert.Single(SelectedItems); + + // Act - Click and select Row 1 Cell 0 + await ClickOnCellAsync(cut, row: 1, cell: 0); + Assert.Single(cut.FindAll("svg[row-selected]")); + Assert.Single(SelectedItems); + } + + [Fact] + public async Task FluentDataGrid_ColumSelect_MultiSelect_SelectedItems_RestrictToCheckbox() + { + IEnumerable SelectedItems = Array.Empty(); + + // Arrange + var cut = Render( + @ + + + + ); + + // Pre-Assert + Assert.Empty(cut.FindAll("svg[row-selected]")); + Assert.Empty(SelectedItems); + + // Act - Click Row 0 Cell 1 + await ClickOnCellAsync(cut, row: 0, cell: 1); + Assert.Empty(cut.FindAll("svg[row-selected]")); + Assert.Empty(SelectedItems); + + // Act - Click and select Row 0 Cell 0 + await ClickOnCellAsync(cut, row: 0, cell: 0); + Assert.Single(cut.FindAll("svg[row-selected]")); + Assert.Single(SelectedItems); + + // Act - Click Row 1 Cell 1 + await ClickOnCellAsync(cut, row: 1, cell: 1); + Assert.Single(cut.FindAll("svg[row-selected]")); + Assert.Single(SelectedItems); + + // Act - Click and select Row 1 Cell 0 + await ClickOnCellAsync(cut, row: 1, cell: 0); + Assert.Equal(2, cut.FindAll("svg[row-selected]").Count); + Assert.Equal(2, SelectedItems.Count()); + } + /// /// Simulate a click on the DataGrid row number . /// @@ -331,6 +413,20 @@ cut.FindComponent>().Render(); } + /// + /// Simulate a click on the DataGrid cell number in row number . + /// + /// + /// + /// + /// + private async Task ClickOnCellAsync(IRenderedFragment cut, int row, int cell) + { + var item = cut.FindComponents>().ElementAt(row + 1).FindComponents>().ElementAt(cell); + await item.Instance.HandleOnCellClickAsync(); + cut.FindComponent>().Render(); + } + /// /// Simulate a click on the All Checkbox. /// From 615ee1dcd50c51a720a8239efa441fe4460d7a15 Mon Sep 17 00:00:00 2001 From: Alessio Dell Aquila Date: Fri, 7 Jun 2024 13:27:38 +0200 Subject: [PATCH 5/5] [DataGrid] Fix requested changes --- ...crosoft.FluentUI.AspNetCore.Components.xml | 10 ++++++++++ .../Examples/DataGridMultiSelect.razor | 19 +++++++++++++------ .../DataGrid/FluentDataGrid.razor.cs | 6 +++--- .../DataGrid/FluentDataGridCell.razor | 1 - .../DataGrid/FluentDataGridCell.razor.cs | 18 ++++++------------ 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml index 7fc8190d9e..14f91e9c36 100644 --- a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml +++ b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml @@ -1490,6 +1490,16 @@ + + + Allows to clear the selection. + + + + + Allows to clear the selection. + + diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor index a37460ebda..4bba452177 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridMultiSelect.razor @@ -14,8 +14,11 @@ @* Sample using SelectedItems *@
Using SelectedItems
- - + @@ -34,8 +37,11 @@ else @* Sample using Property and OnSelect *@
Using Property and OnSelect
- - + ? SelectColumn; + bool UseSelectedItems = true; DataGridSelectMode Mode = DataGridSelectMode.Single; @@ -78,7 +86,6 @@ else private void ResetSelectItems() { People.ToList().ForEach(i => i.Selected = false); - People.First().Selected = true; - SelectedItems = People.Where(p => p.Selected); + SelectColumn?.ClearSelection(); } } diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs index 706390355d..9ebbb75812 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs @@ -382,7 +382,7 @@ public Task SortByColumnAsync(ColumnBase column, SortDirection direct /// The direction of sorting. The default is . If the value is , then it will toggle the direction on each call. public Task SortByColumnAsync(string title, SortDirection direction = SortDirection.Auto) { - var column = _columns.FirstOrDefault(c => c.Title?.Equals(title, StringComparison.InvariantCultureIgnoreCase) ?? false); + var column = Columns.FirstOrDefault(c => c.Title?.Equals(title, StringComparison.InvariantCultureIgnoreCase) ?? false); if (column is not null) { @@ -399,9 +399,9 @@ public Task SortByColumnAsync(string title, SortDirection direction = SortDirect /// The direction of sorting. The default is . If the value is , then it will toggle the direction on each call. public Task SortByColumnAsync(int index, SortDirection direction = SortDirection.Auto) { - if (index >= 0 && index < _columns.Count) + if (index >= 0 && index < Columns.Count) { - return SortByColumnAsync(_columns[index], direction); + return SortByColumnAsync(Columns[index], direction); } return Task.CompletedTask; diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor b/src/Core/Components/DataGrid/FluentDataGridCell.razor index 18a9c9a815..e94605961d 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor @@ -7,7 +7,6 @@ class="@Class" style="@StyleValue" @onclick="@HandleOnCellClickAsync" - @onclick:stopPropagation="StopClickPropagation()" @attributes="AdditionalAttributes"> @ChildContent diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs index 8945b20bc6..3b08bd1ec4 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs @@ -61,13 +61,6 @@ protected override void OnInitialized() public void Dispose() => Owner.Unregister(this); - private bool StopClickPropagation() - { - var selColumn = Owner.Owner.Grid.SelectColumns.FirstOrDefault(); - - return selColumn != null && selColumn.RestrictToCheckbox is true && Owner.Owner.Grid.Columns.IndexOf(selColumn) == GridColumn - 1; - } - /// internal async Task HandleOnCellClickAsync() { @@ -76,13 +69,14 @@ internal async Task HandleOnCellClickAsync() await GridContext.Grid.OnCellClick.InvokeAsync(this); } - if (CellType == DataGridCellType.Default) + if (CellType == DataGridCellType.Default && Owner.Owner.Grid.SelectColumns.Any(selColumn => selColumn.RestrictToCheckbox)) { - var selColumn = Owner.Owner.Grid.SelectColumns.FirstOrDefault(); - - if (selColumn != null && selColumn.RestrictToCheckbox is true && Owner.Owner.Grid.Columns.IndexOf(selColumn) == GridColumn - 1) + foreach (var selColumn in Owner.Owner.Grid.SelectColumns) { - await selColumn.AddOrRemoveSelectedItemAsync(Item); + if (selColumn != null && selColumn.RestrictToCheckbox is true && Owner.Owner.Grid.Columns.IndexOf(selColumn) == GridColumn - 1) + { + await selColumn.AddOrRemoveSelectedItemAsync(Item); + } } } }