Skip to content

[dev-v5] Add DataGrid - part 4, docs and examples #3971

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

Draft
wants to merge 71 commits into
base: dev-v5
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
93f6cf9
- Add enums
vnbaaij Jun 12, 2025
b255f69
- Add DataGrid component
vnbaaij Jun 12, 2025
96e40df
Add DataGridGeneratedHeaderType
vnbaaij Jun 12, 2025
f6d0fb1
Merge branch 'users/vnbaaij/dev-v5/datagrid-part1' into users/vnbaaij…
vnbaaij Jun 12, 2025
1059dbe
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part1
dvoituron Jun 12, 2025
595ff78
Fix analyzer errors
vnbaaij Jun 12, 2025
b1cf680
- Add Typical demo and flags
vnbaaij Jun 12, 2025
8393e35
Work on review comments
vnbaaij Jun 12, 2025
8cd48c6
Merge branch 'users/vnbaaij/dev-v5/datagrid-part1' of https://github.…
vnbaaij Jun 12, 2025
202c10a
Process review comments
vnbaaij Jun 12, 2025
5aa2c65
Add language resources
vnbaaij Jun 12, 2025
777e854
Add Unit Tests for Paginator
vnbaaij Jun 12, 2025
448c89e
More review comments
vnbaaij Jun 13, 2025
3146aeb
Update tests. Now 100% lc
vnbaaij Jun 13, 2025
69ffae6
- Add Typical demo and flags
vnbaaij Jun 13, 2025
35e0334
Replace tokens (WIP)
vnbaaij Jun 13, 2025
b92c83c
Remove flags. These will be added to sample data project in separate PR
vnbaaij Jun 17, 2025
430abd5
Remove DI abstractions package. Not needed
vnbaaij Jun 17, 2025
d0c1052
Merge dev-v5
vnbaaij Jun 17, 2025
33af462
Add IsFixed parameter
vnbaaij Jun 17, 2025
689fe43
merge dev-v5
vnbaaij Jun 17, 2025
44f7d0d
MAke example grid mor functional and look better
vnbaaij Jun 17, 2025
6fc0809
Add initial tests. They are not passing yet
vnbaaij Jun 18, 2025
5bcb9fa
Add surpression atribute, fix other analyzer warnings
vnbaaij Jun 18, 2025
a30dabf
Use localized strings
vnbaaij Jun 18, 2025
aadf080
Merg dev-v5
vnbaaij Jun 18, 2025
70c342b
Fix tests
vnbaaij Jun 18, 2025
b826128
Add Tests
vnbaaij Jun 19, 2025
d0979ea
Add tests for PaginatinState and TotalItemCountChangedEventArgs
vnbaaij Jun 19, 2025
a6aa6fc
Merge branch 'users/vnbaaij/dev-v5/pagination-tests' into users/vnbaa…
vnbaaij Jun 19, 2025
613cbd0
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/pagination-tests
vnbaaij Jun 19, 2025
af4f1e8
Add Row tests
vnbaaij Jun 19, 2025
89038a7
process review comments
vnbaaij Jun 19, 2025
bcdffd9
Merge branch 'users/vnbaaij/dev-v5/pagination-tests' into users/vnbaa…
vnbaaij Jun 19, 2025
ba9c0fb
More tests
vnbaaij Jun 19, 2025
924df75
More tests
vnbaaij Jun 19, 2025
726cf24
Merge branch 'users/vnbaaij/dev-v5/datagrid-part2' of https://github.…
vnbaaij Jun 20, 2025
8fe02c0
- Add typical demo
vnbaaij Jun 23, 2025
abb696c
More tests
vnbaaij Jun 29, 2025
4aae12f
- More tests
vnbaaij Jun 29, 2025
39dc140
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part2
vnbaaij Jul 1, 2025
f4b691a
Update file headers
vnbaaij Jul 1, 2025
1f50f07
Convert DataGrid JS to TS
vnbaaij Jul 1, 2025
097db2f
Implement fix for #3963
vnbaaij Jul 1, 2025
713d96b
Bring in changes made in v4 with #3949
vnbaaij Jul 1, 2025
2698837
- Update file headers
vnbaaij Jul 1, 2025
460a82f
Merge branch 'users/vnbaaij/dev-v5/datagrid-part2' into users/vnbaaij…
vnbaaij Jul 1, 2025
f9ce111
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part3
vnbaaij Jul 2, 2025
ab02f1c
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part2
vnbaaij Jul 2, 2025
088dd55
Process review comments:
vnbaaij Jul 2, 2025
ede49e6
Forgot to change the docs
vnbaaij Jul 2, 2025
87cb81a
Merge branch 'users/vnbaaij/dev-v5/datagrid-part2' into users/vnbaaij…
vnbaaij Jul 2, 2025
d47fc5e
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part2
vnbaaij Jul 2, 2025
f921191
- Use auto-generated constant
vnbaaij Jul 2, 2025
25e046e
Merge branch 'users/vnbaaij/dev-v5/datagrid-part2' of https://github.…
vnbaaij Jul 2, 2025
e6ec4a3
DataGrid docs and examples
vnbaaij Jul 2, 2025
07365bd
Merge branch 'users/vnbaaij/dev-v5/datagrid-part3' into users/vnbaaij…
vnbaaij Jul 2, 2025
5af4579
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part4
vnbaaij Jul 2, 2025
66af301
Merge branch 'users/vnbaaij/dev-v5/datagrid-part2' into users/vnbaaij…
vnbaaij Jul 3, 2025
9e89b82
Merge branch 'users/vnbaaij/dev-v5/datagrid-part3' into users/vnbaaij…
vnbaaij Jul 3, 2025
855fe34
Merge branch 'users/vnbaaij/dev-v5/datagrid-part4' of https://github.…
vnbaaij Jul 3, 2025
e3c942f
Process review comments
vnbaaij Jul 3, 2025
f6d458b
More review comments
vnbaaij Jul 3, 2025
64cf5bb
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/datagrid-part2
vnbaaij Jul 3, 2025
85154bf
- Undo make internal GridItemsProvider*
vnbaaij Jul 3, 2025
ed02449
Update test verified files
vnbaaij Jul 3, 2025
770c533
merge part 2
vnbaaij Jul 3, 2025
c6a2f1b
Merge branch 'users/vnbaaij/dev-v5/datagrid-part3' into users/vnbaaij…
vnbaaij Jul 3, 2025
d0246dd
Merge dev-v5
vnbaaij Jul 3, 2025
36dc27b
- Fix when to show header menu
vnbaaij Jul 3, 2025
150c1fd
- Rename getting started
vnbaaij Jul 3, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#datagrid-container {
height: calc(100% - 3rem);
min-height: 8rem;
overflow-x: auto;
overflow-y: hidden;
}

article {
min-height: 32rem;
max-height: 80dvh;
}

.demo-section-content {
height: calc(100% - 10rem);
}

.demo-section-example {
min-height: 135px !important;
height: 100%;
}

fluent-tabs {
height: 100%;
}

#tab-example-autoitemsperpage-panel {
height: 100% !important;
max-height: calc(100% - 2rem) !important;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@using System.ComponentModel.DataAnnotations

<FluentGrid Spacing="4">
<FluentGridItem xs="12">
<h4>With auto-fit</h4>
<FluentDataGrid Items="@people" Style="width: 100%;" AutoFit="true">
<PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
<PropertyColumn Property="@(p => p.Bio)" />
</FluentDataGrid>
</FluentGridItem>
<FluentGridItem xs="12">
<h4>Without auto-fit</h4>
<FluentDataGrid Items="@people">
<PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
<PropertyColumn Property="@(p => p.Bio)" />
</FluentDataGrid>
</FluentGridItem>
</FluentGrid>

@code {
public class Person
{
public Person(int personId, string name, DateOnly birthDate, string bio)
{
PersonId = personId;
Name = name;
BirthDate = birthDate;
Bio = bio;
}

[Display(Name = "Identity")]
public int PersonId { get; set; }

[Display(Name = "Name")]
public string Name { get; set; }

[Display(Name = "Birth date")]
public DateOnly BirthDate { get; set; }

[Display(Name = "Biography")]
public string Bio { get; set; }
}

IQueryable<Person> people = new[]
{
new Person(10895, "Jean Martin", new DateOnly(1825, 11, 29), "Born on November 29, 1825, in Paris, France, is renowned as the founder of modern neurology."),
new Person(10944, "António Langa", new DateOnly(1972, 5, 15), "Born on May 15, 1972, in Columbia, South Carolina, is a distinguished former professional basketball player."),
new Person(11203, "Julie Smith", new DateOnly(1944, 11, 25), "Born on November 25, 1944, in Annapolis, Maryland, is an acclaimed American mystery writer celebrated for her rich storytelling."),
new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27), "Nur Sari is a fictional character known for her extraordinary contributions to the field of renewable energy."),
new Person(11898, "Jose Hernandez", new DateOnly(1962, 8, 7), "Born on August 7, 1962, in French Camp, California, is a Mexican-American engineer."),
new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9), ""),
}.AsQueryable();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@using static FluentUI.Demo.SampleData.Olympics2024

@inject IJSRuntime JSRuntime

<div id="datagrid-container">
<FluentDataGrid Items="items!.AsQueryable()"
Pagination="@pagination"
RowSize="@rowSize"
AutoItemsPerPage="true"
Style="overflow-y:hidden;">
<PropertyColumn Property="@(c => c.Code)" Sortable="true" />
<PropertyColumn Property="@(c => c.Medals.Gold)" Sortable="true" />
<PropertyColumn Property="@(c => c.Medals.Silver)" Sortable="true" />
<PropertyColumn Property="@(c => c.Medals.Bronze)" Sortable="true" />
<PropertyColumn Property="@(c => c.Medals.Total)" Sortable="true" />
</FluentDataGrid>
</div>

<FluentPaginator State="@pagination" />

@code {

DataGridRowSize rowSize = DataGridRowSize.Small;
IQueryable<Country>? items;
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };

protected override void OnInitialized() =>
items = SampleData.Olympics2024.Countries.AsQueryable();

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@using System.ComponentModel.DataAnnotations
<FluentDataGrid Items="@people">
<PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
</FluentDataGrid>

@code {
public class Person
{
public Person(int personId, string name, DateOnly birthDate)
{
PersonId = personId;
Name = name;
BirthDate = birthDate;
}

[Display(Name="Identity")]
public int PersonId { get; set; }

[Display(Name = "Full _name")]
public string Name { get; set; }

[Display(Name = "Birth date")]
public DateOnly BirthDate { get; set; }
}

IQueryable<Person> people = new[]
{
new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)),
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();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<FluentDataGrid Items="@_gridData" ResizableColumns=true GridTemplateColumns="0.5fr 0.5fr">
<TemplateColumn Sortable="true" Title="First Name" SortBy="_firstNameSort">
@context.Properties["firstname"]
</TemplateColumn>

<TemplateColumn Sortable="true" Title="Last Name" SortBy="_lastNameSort">
@context.Properties["lastname"]
</TemplateColumn>
</FluentDataGrid>

@code {
private ColumnKeyGridSort<GridRow> _firstNameSort = new ColumnKeyGridSort<GridRow>(
"firstname",
(queryable, sortAscending) =>
{
if (sortAscending)
{
return queryable.OrderBy(x => x.Properties["firstname"]);
}
else
{
return queryable.OrderByDescending(x => x.Properties["firstname"]);
}
}
);

private ColumnKeyGridSort<GridRow> _lastNameSort = new ColumnKeyGridSort<GridRow>(
"lastname",
(queryable, sortAscending) =>
{
if (sortAscending)
{
return queryable.OrderBy(x => x.Properties["lastname"]);
}
else
{
return queryable.OrderByDescending(x => x.Properties["lastname"]);
}
}
);

private static readonly IQueryable<GridRow> _gridData = new GridRow[] {
new(new Dictionary<string, string>{ { "firstname", "Tom" }, { "lastname", "Cruise" } }),
new(new Dictionary<string, string>{ { "firstname", "Dolly" }, { "lastname", "Parton" } }),
new(new Dictionary<string, string>{ { "firstname", "Nicole" }, { "lastname", "Kidmon" } }),
new(new Dictionary<string, string>{ { "firstname", "James" }, { "lastname", "Bond" } }),
}.AsQueryable();

public record GridRow(Dictionary<string, string> Properties);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
@using static FluentUI.Demo.SampleData.Olympics2024

@if (altcolor)
{
<style>
:root {
--datagrid-hover-color: lightyellow;

}

.fluent-data-grid {
--fluent-data-grid-resize-handle-color: var(--neutral-stroke-rest) !important;
}
</style>

}


<FluentStack>
<FluentRadioGroup Name="rt" @bind-Value="@_resizeType" Label="Resize type">
<FluentRadio Value="@DataGridResizeType.Discrete">Discrete</FluentRadio>
<FluentRadio Value="@DataGridResizeType.Exact">Exact</FluentRadio>
</FluentRadioGroup>
<FluentSpacer Width="25" />
<FluentCheckbox @bind-Value="@_showActionsMenu" Label="Use menu for column actions" />
<FluentCheckbox @bind-Value="@_useMenuService" Label="Use service for rendering menu" Disabled="!_showActionsMenu" />
<FluentCheckbox @bind-Value="@_resizeColumnOnAllRows" Label="Resize column on all rows" />
</FluentStack>

<div style="height: 400px; overflow-x:auto; display:flex;">
<FluentDataGrid Items="@FilteredItems"
ResizableColumns=true
ResizeType="@_resizeType"
ResizeColumnOnAllRows="@_resizeColumnOnAllRows"
HeaderCellAsButtonWithMenu="_showActionsMenu"
UseMenuService="_useMenuService"
Pagination="@pagination"
TGridItem="Country"
OnRowFocus="HandleRowFocus"
GridTemplateColumns="0.2fr 1fr 0.2fr 0.2fr 0.2fr 0.2fr"
ShowHover="true">
<TemplateColumn Title="Rank" Sortable="true" SortBy="@rankSort" Align="DataGridCellAlignment.Center">
<img class="flag" src="_content/FluentUI.Demo.Shared/flags/@(context.Code).svg" alt="Flag of @(context.Code)" />
</TemplateColumn>
<PropertyColumn Property="@(c => c.Name)" InitialSortDirection=DataGridSortDirection.Descending Sortable="true" IsDefaultSortColumn=true Comparer="@StringLengthComparer.Instance" Filtered="!string.IsNullOrWhiteSpace(nameFilter)">
<ColumnOptions>
<div class="search-box">
<FluentTextInput type="search" Autofocus=true @bind-Value=nameFilter @oninput="HandleCountryFilter" @bind-Value:after="HandleClear" Placeholder="Country name..." />
</div>
</ColumnOptions>
</PropertyColumn>
@* <TemplateColumn Title="Name" InitialSortDirection=SortDirection.Descending SortBy="@nameSort" IsDefaultSortColumn=true Filtered="!string.IsNullOrWhiteSpace(nameFilter)">
<ColumnOptions>
<div class="search-box">
<FluentSearch type="search" Autofocus=true @bind-Value=nameFilter @oninput="HandleCountryFilter" @bind-Value:after="HandleClear" Placeholder="Country name..." />
</div>
</ColumnOptions>
<ChildContent>
@(context.Name)
</ChildContent>
</TemplateColumn> *@
<PropertyColumn Property="@(c => c.Medals.Gold)" Sortable="true" Align="DataGridCellAlignment.Start" />
<PropertyColumn Property="@(c => c.Medals.Silver)" Sortable="true" Align="DataGridCellAlignment.Center" />
<PropertyColumn Property="@(c => c.Medals.Bronze)" Sortable="true" Align="DataGridCellAlignment.End" />
<PropertyColumn Property="@(c => c.Medals.Total)" Sortable="true" Align="DataGridCellAlignment.End" />
</FluentDataGrid>
</div>

<FluentPaginator State="@pagination">
<SummaryTemplate>
There are <strong>@(pagination.TotalItemCount ?? 0)</strong> rows
</SummaryTemplate>
<PaginationTextTemplate>
This is page <strong>@(pagination.CurrentPageIndex + 1)</strong> out of a total of <strong>@(pagination.LastPageIndex + 1)</strong> pages
</PaginationTextTemplate>
</FluentPaginator>

<FluentSwitch @bind-Value="altcolor" Label="Alternative hover color"></FluentSwitch>


@code {
bool altcolor = false;
IQueryable<Country>? items;
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
string nameFilter = string.Empty;
DataGridResizeType? _resizeType = null;
bool _showActionsMenu;
bool _useMenuService = true;
bool _resizeColumnOnAllRows = true;

GridSort<Country> rankSort = GridSort<Country>
.ByDescending(x => x.Medals.Gold)
.ThenDescending(x => x.Medals.Silver)
.ThenDescending(x => x.Medals.Bronze);

// Uncomment line below when using the TemplateColumn example for the country _name
//GridSort<Country> nameSort = GridSort<Country>.ByAscending(x => x.Name, StringLengthComparer.Instance);


IQueryable<Country>? FilteredItems => items?.Where(x => x.Name.Contains(nameFilter, StringComparison.CurrentCultureIgnoreCase));

protected override void OnInitialized()
{
items = SampleData.Olympics2024.Countries.AsQueryable();
}

private void HandleCountryFilter(ChangeEventArgs args)
{
if (args.Value is string value)
{
nameFilter = value;
}
}

private void HandleClear()
{
if (string.IsNullOrWhiteSpace(nameFilter))
{
nameFilter = string.Empty;
}
}

private void HandleRowFocus(FluentDataGridRow<Country> row)
{
Console.WriteLine($"[Custom comparer] Row focused: {row.Item?.Name}");
}

public class StringLengthComparer : IComparer<string>
{
public static readonly StringLengthComparer Instance = new StringLengthComparer();

public int Compare(string? x, string? y)
{
if (x is null)
{
return y is null ? 0 : -1;
}

if (y is null)
{
return 1;
}

return x.Length.CompareTo(y.Length);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* Ensure all the flags are the same size, and centered */
.flag {
height: 1rem;
margin: auto;
border: 1px solid var(--neutral-layer-3);
}
Loading
Loading