Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Multiselect feature, adding a SelectColumn #1952

Merged
merged 33 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a113c59
Add SelectRowColumn column
dvoituron Apr 26, 2024
81177cd
Including Icons
dvoituron Apr 26, 2024
3e233e2
Update the colum name to SelectColumn and use a EventCallback
dvoituron Apr 26, 2024
ef233bc
Adding TGridItem="Person"
dvoituron Apr 26, 2024
5524506
Add SelectAllChanged
dvoituron Apr 26, 2024
fc2f225
Add a bindable SelectAll property
dvoituron Apr 26, 2024
ac38417
Remove AllSelected demo var
dvoituron Apr 26, 2024
888a78e
Merge branch 'dev' into users/datagrid/multi-select
dvoituron Apr 26, 2024
696923e
Merge branch 'dev' into users/datagrid/multi-select
vnbaaij Apr 26, 2024
4bf3bbf
Add Style
dvoituron Apr 26, 2024
0b38e8c
Fix the sample
dvoituron Apr 26, 2024
f110762
Merge branch 'users/datagrid/multi-select' of github.com-perso:micros…
dvoituron Apr 26, 2024
cbfe3c1
Add IconIndeterminate
dvoituron Apr 26, 2024
0b47a07
Replace by IEnumerable
dvoituron Apr 26, 2024
5ed9696
Add DataGridSelectMode.Single
dvoituron Apr 26, 2024
50068f9
Merge branch 'dev' into users/datagrid/multi-select
dvoituron Apr 28, 2024
c8daac0
Separated the SelectedItems and Property / OnSelect (not yet completed)
dvoituron Apr 28, 2024
fc271b7
Update
dvoituron Apr 28, 2024
1b83879
Update the 2 examples
dvoituron Apr 28, 2024
0229a57
Add Titles
dvoituron Apr 28, 2024
489af95
Add OnRowDoubleClick
dvoituron Apr 28, 2024
3c1a8ac
Add Enter key
dvoituron Apr 28, 2024
04881be
Update keys to select/unselect
dvoituron Apr 28, 2024
5c87496
Merge branch 'dev' into users/datagrid/multi-select
dvoituron Apr 28, 2024
d360e7e
Update doc
dvoituron Apr 28, 2024
323f2c3
Add first Unit Test
dvoituron Apr 29, 2024
e275763
Add Unit Tests
dvoituron Apr 29, 2024
56d3a89
Add Unit Tests for Property attribute
dvoituron Apr 29, 2024
4f3e2cc
Merge branch 'dev' into users/datagrid/multi-select
dvoituron Apr 29, 2024
cf19e3f
Add SwitchMultiToSingleSelect
dvoituron Apr 29, 2024
6473d6e
Update the doc
dvoituron Apr 29, 2024
c927720
Update Single Icons and Doc (PR comments)
dvoituron Apr 30, 2024
1ae2d38
Merge branch 'dev' into users/datagrid/multi-select
vnbaaij Apr 30, 2024
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
178 changes: 178 additions & 0 deletions examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,142 @@
<member name="M:Microsoft.FluentUI.AspNetCore.Components.PropertyColumn`2.CellContent(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder,`0)">
<inheritdoc />
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1">
<summary>
Represents a <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/> column whose cells render a selected checkbox updated when the user click on a row.
</summary>
<typeparam name="TGridItem">The type of data represented by each row in the grid.</typeparam>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.KEYBOARD_SELECT_KEYS">
<summary>
List of keys to press, to select/unselect a row.
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.#ctor">
<summary>
Initializes a new instance of <see cref="T:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1"/>.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.ChildContent">
<summary>
Gets or sets the content to be rendered for each row in the table.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SelectedItems">
<summary>
Gets or sets the list of selected items.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SelectedItemsChanged">
<summary>
Gets or sets a callback when list of selected items changed.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SelectMode">
<summary>
Gets or sets the selection mode (Single or Multiple).
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.IconUnchecked">
<summary>
Gets or sets the Icon to be rendered when the row is non selected.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.TitleUnchecked">
<summary>
Gets or sets the Icon title display as a tooltip and used with Accessibility.
The default text is "Row unselected".
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.IconChecked">
<summary>
Gets or sets the Icon to be rendered when the row is selected.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.TitleChecked">
<summary>
Gets or sets the Icon title display as a tooltip and used with Accessibility.
The default text is "Row selected".
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.IconIndeterminate">
<summary>
Gets or sets the Icon to be rendered when some but not all rows are selected.
Only when <see cref="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SelectMode"/> is Multiple.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.TitleAllChecked">
<summary>
Gets or sets the Icon title display as a tooltip and used with Accessibility.
The default text is "All rows are selected.".
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.TitleAllUnchecked">
<summary>
Gets or sets the Icon title display as a tooltip and used with Accessibility.
The default text is "No rows are selected.".
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.TitleAllIndeterminate">
<summary>
Gets or sets the Icon title display as a tooltip and used with Accessibility.
The default text is "Some rows are selected.".
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.OnSelect">
<summary>
Gets or sets the action to be executed when the row is selected or unselected.
This action is required to update you data model.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SelectAll">
<summary>
Gets or sets the value indicating whether the [All] checkbox is selected.
Null is undefined.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SelectAllChanged">
<summary>
Gets or sets the action to be executed when the [All] checkbox is clicked.
When this action is defined, the [All] checkbox is displayed.
This action is required to update you data model.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.Property">
<summary>
Gets or sets the function to be executed to display the checked/unchecked icon, depending of you data model.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.SortBy">
<inheritdoc />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.AddOrRemoveSelectedItemAsync(`0)">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.GetDefaultChildContent">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.GetHeaderContent">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.RefreshHeaderContent">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.GetSelectAll">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.CellContent(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder,`0)">
<inheritdoc />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.RawCellContent(`0)">
<inheritdoc />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.IsSortableByDefault">
<inheritdoc />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1.OnClickAllAsync(Microsoft.AspNetCore.Components.Web.MouseEventArgs)">
<summary />
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.SortedProperty">
<summary>
Holds the name of a property and the direction to sort by.
Expand Down Expand Up @@ -1500,6 +1636,16 @@
Gets or sets a callback when a row is focused.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.OnRowClick">
<summary>
Gets or sets a callback when a row is clicked.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.OnRowDoubleClick">
<summary>
Gets or sets a callback when a row is double-clicked.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.RowClass">
<summary>
Optionally defines a class to be applied to a rendered row.
Expand All @@ -1511,6 +1657,11 @@
Do not use to dynamically update a row style after rendering as this will interfere with the script that use this attribute. Use <see cref="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.RowClass"/> instead.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.ShowHover">
<summary>
Gets or sets a value indicating whether the grid should show a hover effect on rows.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.EmptyContent">
<summary>
If specified, grids render this fragment when there is no content.
Expand All @@ -1527,6 +1678,11 @@
A default fragment is used if loading content is not specified.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.SelectColumns">
<summary>
Gets the first (optional) SelectColumn
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.#ctor">
<summary>
Constructs an instance of <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/>.
Expand Down Expand Up @@ -1632,6 +1788,18 @@
Gets or sets the owning <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/> component
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1.HandleOnRowClickAsync(System.String)">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1.HandleOnRowDoubleClickAsync(System.String)">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1.HandleOnRowKeyDownAsync(System.String,Microsoft.AspNetCore.Components.Web.KeyboardEventArgs)">
<summary />
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1.Microsoft#AspNetCore#Components#IHandleEvent#HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem,System.Object)">
<summary />
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.GridItemsProvider`1">
<summary>
A callback that provides data for a <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/>.
Expand Down Expand Up @@ -11771,6 +11939,16 @@
A sticky header row.
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.DataGridSelectMode.Single">
<summary>
Allow only one selected row.
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.DataGridSelectMode.Multiple">
<summary>
Allow multiple selected rows.
</summary>
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.DesignThemeModes">
<summary>
The standard theme values for light and dark mode.
Expand Down
42 changes: 42 additions & 0 deletions examples/Demo/Shared/Pages/DataGrid/DataGridPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
width is done in steps of 10 pixels at a time. You can reset to the original initial column widths by pressing <kbd>Shift</kbd> + <kbd>r</kbd>.
</p>

<p>
When a row cell is focused and the grid contains a <code>SelectColumn</code> column, you can use the <kbd>Enter</kbd> key to select or unselect the current row.
</p>

<h2 id="sorting">Sorting</h2>
<p>
The DataGrid supports sorting by clicking on the column headers. The default sort direction is ascending. Clicking on the same column header again will toggle the sort direction.
Expand All @@ -53,6 +57,42 @@
</Description>
</DemoSection>

<DemoSection Title="Multi Select" Component="@typeof(DataGridMultiSelect)">
<Description>
<p>The same example, adding a <code>SelectColumn</code>, to allow multi-select rows.</p>
<p>To utilize the <b>SelectColumn</b> feature in the Fluent DataGrid, there are two approaches available:</p>

<p>
<b>Automatic Management via <code>SelectedItems</code></b>
<ul>
<li>Provide a list of data via the <code>Items</code> property.</li>
<li>Let the grid handle selected rows entirely through the <code>SelectedItems</code> property.</li>
</ul>
</p>
<p>
<b>Manual Management via <code>Property</code> and <code>OnSelect</code>:</b>
<ul>
<li>Control how selected lines are saved manually.</li>
<li>Utilize the <code>Property</code>, <code>OnSelect</code>, and <code>SelectAll</code> attributes.</li>
</ul>
This method offers more flexibility but requires additional configuration, making it particularly useful when
using <code>Virtualize</code> or directly managing a custom <code>IsSelected</code> property.
</p>

<blockquote>
By default the Fluent Design System recommends to only use the checkbox to indicate selected rows.
It is possible to change this behavior by using a CSS style like this to set a background on selected rows:
<code>
<pre>
fluent-data-grid-row:has([row-selected]) {
background-color: var(--neutral-fill-stealth-hover)
}</pre>
</code>
</blockquote>

</Description>
</DemoSection>

<DemoSection Title="Typical usage" Component="@typeof(DataGridTypical)" CollocatedFiles="@(new[] {"css"})">
<Description>
<p>
Expand Down Expand Up @@ -229,6 +269,8 @@

<ApiDocumentation Component="typeof(TemplateColumn<>)" GenericLabel="TGridItem" />

<ApiDocumentation Component="typeof(SelectColumn<>)" GenericLabel="TGridItem" />

<div class="demopanel">
<p>
<strong>The <code>FluentDataGridRow</code> and <code>FluentDataGridCell</code> API's are usually not used directely </strong>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<FluentStack VerticalAlignment="VerticalAlignment.Center">
<FluentSelect Items="@(Enum.GetValues<DataGridSelectMode>())"
@bind-SelectedOption="@Mode" />
<FluentCheckbox @bind-Value="@UseSelectedItems"
@bind-Value:after="@(() => ResetSelectItems())"
Label="Use `SelectedItems` property" />
</FluentStack>

@if (UseSelectedItems)
{
@* Sample using SelectedItems *@
<div>Using SelectedItems</div>

<FluentDataGrid Items="@People" ShowHover="true" TGridItem="Person">
<SelectColumn TGridItem="Person"
SelectMode="@Mode"
@bind-SelectedItems="@SelectedItems" />
<PropertyColumn Width="100px" Property="@(p => p.PersonId)" Title="ID" />
<PropertyColumn Width="300px" Property="@(p => p.Name)" />
<PropertyColumn Width="150px" Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
</FluentDataGrid>

<div>
<b>SelectedItems:</b>
@String.Join("; ", SelectedItems.Select(p => p.Name))
</div>
}
else
{
@* Sample using Property and OnSelect *@
<div>Using Property and OnSelect</div>

<FluentDataGrid Items="@People" ShowHover="true" TGridItem="Person">
<SelectColumn TGridItem="Person"
SelectMode="@Mode"
Property="@(e => e.Selected)"
OnSelect="@(e => e.Item.Selected = e.Selected)"
SelectAll="@(People.All(p => p.Selected))"
SelectAllChanged="@(all => People.ToList().ForEach(p => p.Selected = (all == true)))" />
<PropertyColumn Width="100px" Property="@(p => p.PersonId)" Title="ID" />
<PropertyColumn Width="300px" Property="@(p => p.Name)" />
<PropertyColumn Width="150px" Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
</FluentDataGrid>

<div>
<b>Peoples:</b>
@String.Join("; ", People.Where(p => p.Selected).Select(p => p.Name))
</div>
}

@code {
bool UseSelectedItems = true;
DataGridSelectMode Mode = DataGridSelectMode.Single;

IEnumerable<Person> SelectedItems = People.Where(p => p.Selected);

record Person(int PersonId, string Name, DateOnly BirthDate)
{
public bool Selected { get; set; }
};

static IQueryable<Person> People = new[]
{
new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)) { Selected = true },
new Person(10944, "António Langa", new DateOnly(1991, 12, 1)),
new Person(11203, "Julie Smith", new DateOnly(1958, 10, 10)),
new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27)),
new Person(11898, "Jose Hernandez", new DateOnly(2011, 5, 3)),
new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9)),
}.AsQueryable();

private void ResetSelectItems()
{
People.ToList().ForEach(i => i.Selected = false);
People.First().Selected = true;
SelectedItems = People.Where(p => p.Selected);
}
}
4 changes: 4 additions & 0 deletions src/Core/BindAttributes.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using Microsoft.AspNetCore.Components;

// Specifies that types that are ordinarily visible only within the current assembly
// are visible to the UnitTest assembly.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Microsoft.FluentUI.AspNetCore.Components.Tests")]

namespace Microsoft.FluentUI.AspNetCore.Components;

// Checkbox like items
Expand Down
Loading
Loading