# DataGridLegacy ## Description BitDataGridLegacy is a robust way to display an information-rich collection of items, and allow people to sort, and filter the content. Use a data-grid when information density is critical. ## Parameters | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | ChildContent | `RenderFragment?` | null | Defines the child components of this instance. For example, you may define columns by adding components derived from the BitDataGridLegacyColumnBase<TGridItem>. | | Class | `string?` | null | An optional CSS class name. If given, this will be included in the class attribute of the rendered table. | | Columns | `RenderFragment?` | null | Alias of the ChildContent parameter. | | ItemKey | `Func<TGridItem, object>` | x => x! | Optionally defines a value for @key on each rendered row. Typically this should be used to specify a unique identifier, such as a primary key value, for each data item. This allows the grid to preserve the association between row elements and data items based on their unique identifiers, even when the TGridItem instances are replaced by new copies (for example, after a new query against the underlying data store). If not set, the @key will be the TGridItem instance itself. | | Items | `IQueryable<TGridItem>?` | null | A queryable source of data for the grid. This could be in-memory data converted to queryable using the System.Linq.Queryable.AsQueryable(System.Collections.IEnumerable) extension method, or an EntityFramework DataSet or an IQueryable derived from it. You should supply either Items or ItemsProvider, but not both. | | ItemSize | `float` | 50 | This is applicable only when using Virtualize. It defines an expected height in pixels for each row, allowing the virtualization mechanism to fetch the correct number of items to match the display size and to ensure accurate scrolling. | | ItemsProvider | `BitDataGridItemsProvider<TGridItem>?` | null | A callback that supplies data for the grid. You should supply either Items or ItemsProvider, but not both. | | LoadingTemplate | `RenderFragment?` | null | The custom template to render while loading the new items. | | Pagination | `BitDataGridLegacyPaginationState?` | null | Optionally links this BitDataGridLegacy<TGridItem> instance with a BitDataGridLegacyPaginationState model, causing the grid to fetch and render only the current page of data. This is normally used in conjunction with a Paginator component or some other UI logic that displays and updates the supplied BitDataGridLegacyPaginationState instance. | | ResizableColumns | `bool` | false | If true, renders draggable handles around the column headers, allowing the user to resize the columns manually. Size changes are not persisted. | | RowClass | `string?` | null | The CSS class of all rows of the BitDataGridLegacy. | | RowClassSelector | `Func<TGridItem, string>?` | null | The function to generate the CSS class of each row of the BitDataGridLegacy. | | RowStyle | `string?` | null | The CSS style of all rows of the BitDataGridLegacy. | | RowStyleSelector | `Func<TGridItem, string>?` | null | The function to generate the CSS style of each row of the BitDataGridLegacy. | | RowTemplate | `RenderFragment<BitDataGridLegacyRowTemplateArgs<TGridItem>>?` | null | Optional template to customize row rendering. Receives BitDataGridLegacyRowTemplateArgs with OriginalRow set to the default row content; render it to include the original row, or omit to replace entirely. | | Theme | `string?` | default | A theme name, with default value "default". This affects which styling rules match the table. | | Virtualize | `bool` | false | If true, the grid will be rendered with virtualization. This is normally used in conjunction with scrolling and causes the grid to fetch and render only the data around the current scroll viewport. This can greatly improve the performance when scrolling through large data sets. | | AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. | | Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. | | Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. | | HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. | | Id | `string?` | null | Gets or sets the unique identifier for the component's root element. | | IsEnabled | `bool` | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. | | Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. | | TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. | | Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. | ## Public Members | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. | | RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. | ## Enums ### BitDataGridLegacyAlign Enum | Name | Value | Description | | :--- | :--- | :---------- | | Left | 0 | Justifies the content against the start of the container. | | Center | 1 | Justifies the content at the center of the container. | | Right | 2 | Justifies the content at the end of the container. | ### BitVisibility Enum | Name | Value | Description | | :--- | :--- | :---------- | | Visible | 0 | The content of the component is visible. | | Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). | | Collapsed | 2 | The component is hidden (display:none). | ### BitDir Enum | Name | Value | Description | | :--- | :--- | :---------- | | Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). | | Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). | | Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. | ## Sub Classes ### BitDataGridLegacyColumnBase Properties BitDataGridLegacy has two built-in column types, BitDataGridLegacyPropertyColumn and BitDataGridLegacyTemplateColumn. You can also create your own column types by subclassing the BitDataGridLegacyColumnBase type, which all columns must derive from. It offers some common parameters. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Title | `string?` | null | Title text for the column. This is rendered automatically if HeaderTemplate is not used. | | Class | `string?` | null | An optional CSS class name. If specified, this is included in the class attribute of table header and body cells for this column. | | Align | `BitDataGridLegacyAlign?` | null | If specified, controls the justification of table header and body cells for this column. | | HeaderTemplate | `RenderFragment<BitDataGridLegacyColumnBase<TGridItem>>?` | null | An optional template for this column's header cell. If not specified, the default header template includes the Title along with any applicable sort indicators and options buttons. | | ColumnOptions | `RenderFragment<BitDataGridLegacyColumnBase<TGridItem>>?` | null | If specified, indicates that this column has this associated options UI. A button to display this UI will be included in the header cell by default. If HeaderTemplate is used, it is left up to that template to render any relevant "show options" UI and invoke the grid's BitDataGridLegacy<TGridItem>.ShowColumnOptions(BitDataGridLegacyColumnBase<TGridItem>). | | Sortable | `bool?` | null | Indicates whether the data should be sortable by this column. The default value may vary according to the column type (for example, a BitDataGridLegacyTemplateColumn<TGridItem> is sortable by default if any BitDataGridLegacyTemplateColumn<TGridItem>.SortBy parameter is specified). | | IsDefaultSort | `BitDataGridLegacySortDirection?` | null | If specified and not null, indicates that this column represents the initial sort order for the grid. The supplied value controls the default sort direction. | | PlaceholderTemplate | `RenderFragment<PlaceholderContext>?` | null | If specified, virtualized grids will use this template to render cells whose data has not yet been loaded. | ### BitDataGridLegacyPropertyColumn Properties It is for displaying a single value specified by the parameter Property. This column infers sorting rules automatically, and uses the property's name as its title if not otherwise set. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Property | `Expression<Func<TGridItem, TProp>>` | | Defines the value to be displayed in this column's cells. | | Format | `string?` | null | Optionally specifies a format string for the value. Using this requires the TProp type to implement IFormattable. | ### BitDataGridLegacyTemplateColumn Properties It uses arbitrary Razor fragments to supply contents for its cells. It can't infer the column's title or sort order automatically. Also, it's possible to add arbitrary Blazor components to your table cells. Remember that rendering many components, or many event handlers, can impact the performance of your grid. One way to mitigate this issue is by paginating or virtualizing your grid. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | ChildContent | `RenderFragment<TGridItem>` | | Specifies the content to be rendered for each row in the table. | | SortBy | `BitDataGridLegacySort<TGridItem>?` | null | Optionally specifies sorting rules for this column. | ### BitDataGridLegacyPaginator Properties A component that provides a user interface for pagination. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | GoToFirstButtonTitle | `string` | Go to first page | The title of the go to first page button. | | GoToPrevButtonTitle | `string` | Go to previous page | The title of the go to previous page button. | | GoToNextButtonTitle | `string` | Go to next page | The title of the go to next page button. | | GoToLastButtonTitle | `string` | Go to last page | The title of the go to last page button. | | SummaryFormat | `Func<BitDataGridLegacyPaginationState, string>?` | null | Optionally supplies a format for rendering the page count summary. | | SummaryTemplate | `RenderFragment<BitDataGridLegacyPaginationState>?` | null | Optionally supplies a template for rendering the page count summary. | | TextFormat | `Func<BitDataGridLegacyPaginationState, string>?` | null | The optional custom format for the main text of the paginator in the middle of it. | | TextTemplate | `RenderFragment<BitDataGridLegacyPaginationState>?` | null | The optional custom template for the main text of the paginator in the middle of it. | | Value | `BitDataGridLegacyPaginationState` | | Specifies the associated pagination state. This parameter is required. | ### BitDataGridLegacyPaginationState Properties Holds state to represent the pagination of a BitDataGridLegacy. Tracks the current page index, the number of items per page, and the total item count so a paginator UI and the grid stay in sync. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | CurrentPageIndex | `int` | 0 | Gets the current zero-based page index. | | ItemsPerPage | `int` | 10 | Gets or sets the number of items on each page. | | LastPageIndex | `int?` | null | Gets the zero-based index of the last page, if known. The value will be null until TotalItemCount is known. | | TotalItemCount | `int?` | null | Gets the total number of items across all pages, if known. The value will be null until an associated BitDataGridLegacy assigns a value after loading data. | | TotalItemCountChanged | `EventHandler<int?>?` | null | An event that is raised when the total item count has changed. | ### BitDataGridLegacyRowTemplateArgs<TGridItem> Properties Arguments passed to the RowTemplate render fragment. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | OriginalRow | `RenderFragment` | | A render fragment that produces the original row markup (the default <tr> with all column cells). Render this to include the default row, or omit to replace entirely. | | RowIndex | `int` | 0 | The 1-based row index used for accessibility (e.g. aria-rowindex). | | RowItem | `TGridItem` | | The data item for this row. | ## Examples \n**Basic**: ```razor ``` ```csharp private IQueryable allCountries; private string typicalSampleNameFilter = string.Empty; private BitDataGridLegacyPaginationState pagination = new() { ItemsPerPage = 7 }; private IQueryable FilteredItems => allCountries?.Where(x => x.Name.Contains(typicalSampleNameFilter ?? string.Empty, StringComparison.CurrentCultureIgnoreCase)); protected override async Task OnInitializedAsync() { allCountries = _countries.AsQueryable(); } private static readonly CountryModel[] _countries = [ new CountryModel { Code = "AR", Name = "Argentina", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "AM", Name = "Armenia", Medals = new MedalsModel { Gold = 0, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "AU", Name = "Australia", Medals = new MedalsModel { Gold = 17, Silver = 7, Bronze = 22 } }, new CountryModel { Code = "AT", Name = "Austria", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "AZ", Name = "Azerbaijan", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 4 } }, new CountryModel { Code = "BS", Name = "Bahamas", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BH", Name = "Bahrain", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "BY", Name = "Belarus", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 3 } }, new CountryModel { Code = "BE", Name = "Belgium", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "BM", Name = "Bermuda", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BW", Name = "Botswana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "BR", Name = "Brazil", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 8 } }, new CountryModel { Code = "BF", Name = "Burkina Faso", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "CA", Name = "Canada", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 11 } }, new CountryModel { Code = "TW", Name = "Chinese Taipei", Medals = new MedalsModel { Gold = 2, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "CO", Name = "Colombia", Medals = new MedalsModel { Gold = 0, Silver = 4, Bronze = 1 } }, new CountryModel { Code = "CI", Name = "Côte d'Ivoire", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HR", Name = "Croatia", Medals = new MedalsModel { Gold = 3, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "CU", Name = "Cuba", Medals = new MedalsModel { Gold = 7, Silver = 3, Bronze = 5 } }, new CountryModel { Code = "CZ", Name = "Czech Republic", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 3 } }, new CountryModel { Code = "DK", Name = "Denmark", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 4 } }, new CountryModel { Code = "DO", Name = "Dominican Republic", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "EC", Name = "Ecuador", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "EE", Name = "Estonia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "ET", Name = "Ethiopia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "FJ", Name = "Fiji", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "FI", Name = "Finland", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "FR", Name = "France", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 11 } }, new CountryModel { Code = "GE", Name = "Georgia", Medals = new MedalsModel { Gold = 2, Silver = 5, Bronze = 1 } }, new CountryModel { Code = "DE", Name = "Germany", Medals = new MedalsModel { Gold = 10, Silver = 11, Bronze = 16 } }, new CountryModel { Code = "GH", Name = "Ghana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "GB", Name = "Great Britain", Medals = new MedalsModel { Gold = 22, Silver = 21, Bronze = 22 } }, new CountryModel { Code = "GR", Name = "Greece", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "GD", Name = "Grenada", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HK", Name = "Hong Kong, China", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 3 } }, new CountryModel { Code = "HU", Name = "Hungary", Medals = new MedalsModel { Gold = 6, Silver = 7, Bronze = 7 } }, new CountryModel { Code = "ID", Name = "Indonesia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "IE", Name = "Ireland", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IR", Name = "Iran", Medals = new MedalsModel { Gold = 3, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "IL", Name = "Israel", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IT", Name = "Italy", Medals = new MedalsModel { Gold = 10, Silver = 10, Bronze = 20 } }, new CountryModel { Code = "JM", Name = "Jamaica", Medals = new MedalsModel { Gold = 4, Silver = 1, Bronze = 4 } }, new CountryModel { Code = "JO", Name = "Jordan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "KZ", Name = "Kazakhstan", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 8 } }, new CountryModel { Code = "KE", Name = "Kenya", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 2 } }, new CountryModel { Code = "XK", Name = "Kosovo", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "KW", Name = "Kuwait", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LV", Name = "Latvia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LT", Name = "Lithuania", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "MY", Name = "Malaysia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "MX", Name = "Mexico", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 4 } }, new CountryModel { Code = "MA", Name = "Morocco", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "NA", Name = "Namibia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NL", Name = "Netherlands", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 14 } }, new CountryModel { Code = "NZ", Name = "New Zealand", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 7 } }, new CountryModel { Code = "MK", Name = "North Macedonia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NO", Name = "Norway", Medals = new MedalsModel { Gold = 4, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "PH", Name = "Philippines", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "PL", Name = "Poland", Medals = new MedalsModel { Gold = 4, Silver = 5, Bronze = 5 } }, new CountryModel { Code = "PT", Name = "Portugal", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "PR", Name = "Puerto Rico", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "QA", Name = "Qatar", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "KR", Name = "Republic of Korea", Medals = new MedalsModel { Gold = 6, Silver = 4, Bronze = 10 } }, new CountryModel { Code = "MD", Name = "Republic of Moldova", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "RO", Name = "Romania", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, new CountryModel { Code = "SM", Name = "San Marino", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "SA", Name = "Saudi Arabia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "RS", Name = "Serbia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "SK", Name = "Slovakia", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "SI", Name = "Slovenia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "ZA", Name = "South Africa", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 0 } }, new CountryModel { Code = "ES", Name = "Spain", Medals = new MedalsModel { Gold = 3, Silver = 8, Bronze = 6 } }, new CountryModel { Code = "SE", Name = "Sweden", Medals = new MedalsModel { Gold = 3, Silver = 6, Bronze = 0 } }, new CountryModel { Code = "CH", Name = "Switzerland", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "SY", Name = "Syrian Arab Republic", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TH", Name = "Thailand", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TR", Name = "Turkey", Medals = new MedalsModel { Gold = 2, Silver = 2, Bronze = 9 } }, new CountryModel { Code = "TM", Name = "Turkmenistan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "UA", Name = "Ukraine", Medals = new MedalsModel { Gold = 1, Silver = 6, Bronze = 12 } }, new CountryModel { Code = "US", Name = "United States of America", Medals = new MedalsModel { Gold = 39, Silver = 41, Bronze = 33 } }, new CountryModel { Code = "UZ", Name = "Uzbekistan", Medals = new MedalsModel { Gold = 3, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "VE", Name = "Venezuela", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, ]; public class CountryModel { public string Code { get; set; } public string Name { get; set; } public MedalsModel Medals { get; set; } } public class MedalsModel { public int Gold { get; set; } public int Silver { get; set; } public int Bronze { get; set; } public int Total => Gold + Silver + Bronze; } ``` \n**Customized**: ```razor
@(context.Code)
@(state.CurrentPageIndex + 1) / @(state.LastPageIndex + 1)
``` ```csharp private IQueryable allCountries; private string typicalSampleNameFilter = string.Empty; private BitDataGridLegacyPaginationState pagination = new() { ItemsPerPage = 7 }; private IQueryable FilteredItems => allCountries?.Where(x => x.Name.Contains(typicalSampleNameFilter ?? string.Empty, StringComparison.CurrentCultureIgnoreCase)); protected override async Task OnInitializedAsync() { allCountries = _countries.AsQueryable(); } private static readonly CountryModel[] _countries = [ new CountryModel { Code = "AR", Name = "Argentina", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "AM", Name = "Armenia", Medals = new MedalsModel { Gold = 0, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "AU", Name = "Australia", Medals = new MedalsModel { Gold = 17, Silver = 7, Bronze = 22 } }, new CountryModel { Code = "AT", Name = "Austria", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "AZ", Name = "Azerbaijan", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 4 } }, new CountryModel { Code = "BS", Name = "Bahamas", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BH", Name = "Bahrain", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "BY", Name = "Belarus", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 3 } }, new CountryModel { Code = "BE", Name = "Belgium", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "BM", Name = "Bermuda", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BW", Name = "Botswana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "BR", Name = "Brazil", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 8 } }, new CountryModel { Code = "BF", Name = "Burkina Faso", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "CA", Name = "Canada", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 11 } }, new CountryModel { Code = "TW", Name = "Chinese Taipei", Medals = new MedalsModel { Gold = 2, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "CO", Name = "Colombia", Medals = new MedalsModel { Gold = 0, Silver = 4, Bronze = 1 } }, new CountryModel { Code = "CI", Name = "Côte d'Ivoire", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HR", Name = "Croatia", Medals = new MedalsModel { Gold = 3, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "CU", Name = "Cuba", Medals = new MedalsModel { Gold = 7, Silver = 3, Bronze = 5 } }, new CountryModel { Code = "CZ", Name = "Czech Republic", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 3 } }, new CountryModel { Code = "DK", Name = "Denmark", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 4 } }, new CountryModel { Code = "DO", Name = "Dominican Republic", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "EC", Name = "Ecuador", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "EE", Name = "Estonia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "ET", Name = "Ethiopia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "FJ", Name = "Fiji", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "FI", Name = "Finland", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "FR", Name = "France", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 11 } }, new CountryModel { Code = "GE", Name = "Georgia", Medals = new MedalsModel { Gold = 2, Silver = 5, Bronze = 1 } }, new CountryModel { Code = "DE", Name = "Germany", Medals = new MedalsModel { Gold = 10, Silver = 11, Bronze = 16 } }, new CountryModel { Code = "GH", Name = "Ghana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "GB", Name = "Great Britain", Medals = new MedalsModel { Gold = 22, Silver = 21, Bronze = 22 } }, new CountryModel { Code = "GR", Name = "Greece", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "GD", Name = "Grenada", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HK", Name = "Hong Kong, China", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 3 } }, new CountryModel { Code = "HU", Name = "Hungary", Medals = new MedalsModel { Gold = 6, Silver = 7, Bronze = 7 } }, new CountryModel { Code = "ID", Name = "Indonesia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "IE", Name = "Ireland", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IR", Name = "Iran", Medals = new MedalsModel { Gold = 3, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "IL", Name = "Israel", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IT", Name = "Italy", Medals = new MedalsModel { Gold = 10, Silver = 10, Bronze = 20 } }, new CountryModel { Code = "JM", Name = "Jamaica", Medals = new MedalsModel { Gold = 4, Silver = 1, Bronze = 4 } }, new CountryModel { Code = "JO", Name = "Jordan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "KZ", Name = "Kazakhstan", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 8 } }, new CountryModel { Code = "KE", Name = "Kenya", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 2 } }, new CountryModel { Code = "XK", Name = "Kosovo", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "KW", Name = "Kuwait", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LV", Name = "Latvia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LT", Name = "Lithuania", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "MY", Name = "Malaysia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "MX", Name = "Mexico", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 4 } }, new CountryModel { Code = "MA", Name = "Morocco", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "NA", Name = "Namibia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NL", Name = "Netherlands", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 14 } }, new CountryModel { Code = "NZ", Name = "New Zealand", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 7 } }, new CountryModel { Code = "MK", Name = "North Macedonia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NO", Name = "Norway", Medals = new MedalsModel { Gold = 4, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "PH", Name = "Philippines", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "PL", Name = "Poland", Medals = new MedalsModel { Gold = 4, Silver = 5, Bronze = 5 } }, new CountryModel { Code = "PT", Name = "Portugal", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "PR", Name = "Puerto Rico", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "QA", Name = "Qatar", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "KR", Name = "Republic of Korea", Medals = new MedalsModel { Gold = 6, Silver = 4, Bronze = 10 } }, new CountryModel { Code = "MD", Name = "Republic of Moldova", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "RO", Name = "Romania", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, new CountryModel { Code = "SM", Name = "San Marino", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "SA", Name = "Saudi Arabia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "RS", Name = "Serbia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "SK", Name = "Slovakia", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "SI", Name = "Slovenia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "ZA", Name = "South Africa", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 0 } }, new CountryModel { Code = "ES", Name = "Spain", Medals = new MedalsModel { Gold = 3, Silver = 8, Bronze = 6 } }, new CountryModel { Code = "SE", Name = "Sweden", Medals = new MedalsModel { Gold = 3, Silver = 6, Bronze = 0 } }, new CountryModel { Code = "CH", Name = "Switzerland", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "SY", Name = "Syrian Arab Republic", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TH", Name = "Thailand", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TR", Name = "Turkey", Medals = new MedalsModel { Gold = 2, Silver = 2, Bronze = 9 } }, new CountryModel { Code = "TM", Name = "Turkmenistan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "UA", Name = "Ukraine", Medals = new MedalsModel { Gold = 1, Silver = 6, Bronze = 12 } }, new CountryModel { Code = "US", Name = "United States of America", Medals = new MedalsModel { Gold = 39, Silver = 41, Bronze = 33 } }, new CountryModel { Code = "UZ", Name = "Uzbekistan", Medals = new MedalsModel { Gold = 3, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "VE", Name = "Venezuela", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, ]; public class CountryModel { public string Code { get; set; } public string Name { get; set; } public MedalsModel Medals { get; set; } } public class MedalsModel { public int Gold { get; set; } public int Silver { get; set; } public int Bronze { get; set; } public int Total => Gold + Silver + Bronze; } ``` \n**Virtualize**: ```razor @using System.Text.Json; @using System.Text.Json.Serialization; @inject HttpClient HttpClient @inject NavigationManager NavManager
``` ```csharp BitDataGridLegacy? dataGrid; string _virtualSampleNameFilter = string.Empty; BitDataGridItemsProvider foodRecallProvider; string VirtualSampleNameFilter { get => _virtualSampleNameFilter; set { _virtualSampleNameFilter = value; _ = dataGrid?.RefreshDataAsync(); } } protected override async Task OnInitializedAsync() { foodRecallProvider = async req => { try { // Strip characters that would break the openFDA Lucene query syntax (the firm name is // wrapped in quotes), namely double quotes and backslashes, before interpolating it. Trim // surrounding whitespace too, since the quoted phrase is matched exactly and stray spaces // would prevent otherwise-valid firm names from matching. var firmFilter = _virtualSampleNameFilter?.Replace("\\", string.Empty).Replace("\""", string.Empty).Trim() ?? string.Empty; var query = new Dictionary { { "skip", req.StartIndex }, { "limit", req.Count ?? 50 } }; // Only add the firm filter when the user typed something; an empty Lucene clause // would suppress the default (unfiltered) results. if (!string.IsNullOrWhiteSpace(firmFilter)) { query.Add("search", $"recalling_firm:\"{firmFilter}\""); } var sort = req.GetSortByProperties().SingleOrDefault(); if (sort != default) { var sortByColumnName = sort.PropertyName switch { nameof(FoodRecall.ReportDate) => "report_date", _ => throw new InvalidOperationException() }; query.Add("sort", $"{sortByColumnName}:{(sort.Direction == BitDataGridLegacySortDirection.Ascending ? "asc" : "desc")}"); } var url = NavManager.GetUriWithQueryParameters("https://api.fda.gov/food/enforcement.json", query); var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.FoodRecallQueryResult, req.CancellationToken); return BitDataGridLegacyItemsProviderResult.From( items: data!.Results, totalItemCount: data!.Meta.Results.Total); } catch (OperationCanceledException) when (req.CancellationToken.IsCancellationRequested) { throw; // a rapid refresh superseded this request; let cancellation flow through } catch { return BitDataGridLegacyItemsProviderResult.From(new List { }, 0); } }; } //https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ [JsonSerializable(typeof(FoodRecallQueryResult))] [JsonSerializable(typeof(Meta))] [JsonSerializable(typeof(FoodRecall))] [JsonSerializable(typeof(Results))] [JsonSerializable(typeof(Openfda))] public partial class AppJsonContext : JsonSerializerContext { } public class FoodRecallQueryResult { [JsonPropertyName("meta")] public Meta? Meta { get; set; } [JsonPropertyName("results")] public List? Results { get; set; } } public class Meta { [JsonPropertyName("disclaimer")] public string? Disclaimer { get; set; } [JsonPropertyName("terms")] public string? Terms { get; set; } [JsonPropertyName("license")] public string? License { get; set; } [JsonPropertyName("last_updated")] public string? LastUpdated { get; set; } [JsonPropertyName("results")] public Results? Results { get; set; } } public class FoodRecall { [JsonPropertyName("country")] public string? CountryModel { get; set; } [JsonPropertyName("city")] public string? City { get; set; } [JsonPropertyName("address_1")] public string? Address1 { get; set; } [JsonPropertyName("reason_for_recall")] public string? ReasonForRecall { get; set; } [JsonPropertyName("address_2")] public string? Address2 { get; set; } [JsonPropertyName("product_quantity")] public string? ProductQuantity { get; set; } [JsonPropertyName("code_info")] public string? CodeInfo { get; set; } [JsonPropertyName("center_classification_date")] public string? CenterClassificationDate { get; set; } [JsonPropertyName("distribution_pattern")] public string? DistributionPattern { get; set; } [JsonPropertyName("state")] public string? State { get; set; } [JsonPropertyName("product_description")] public string? ProductDescription { get; set; } [JsonPropertyName("report_date")] public string? ReportDate { get; set; } [JsonPropertyName("classification")] public string? Classification { get; set; } [JsonPropertyName("openfda")] public Openfda? Openfda { get; set; } [JsonPropertyName("recalling_firm")] public string? RecallingFirm { get; set; } [JsonPropertyName("recall_number")] public string? RecallNumber { get; set; } [JsonPropertyName("initial_firm_notification")] public string? InitialFirmNotification { get; set; } [JsonPropertyName("product_type")] public string? ProductType { get; set; } [JsonPropertyName("event_id")] public string? EventId { get; set; } [JsonPropertyName("more_code_info")] public string? MoreCodeInfo { get; set; } [JsonPropertyName("recall_initiation_date")] public string? RecallInitiationDate { get; set; } [JsonPropertyName("postal_code")] public string? PostalCode { get; set; } [JsonPropertyName("voluntary_mandated")] public string? VoluntaryMandated { get; set; } [JsonPropertyName("status")] public string? Status { get; set; } } public class Results { [JsonPropertyName("skip")] public int Skip { get; set; } [JsonPropertyName("limit")] public int Limit { get; set; } [JsonPropertyName("total")] public int Total { get; set; } } public class Openfda { } ``` \n**OData**: ```razor @using System.Text.Json; @using System.Text.Json.Serialization; @inject HttpClient HttpClient @inject NavigationManager NavManager
``` ```csharp // ========== Server code ========== // To make following aspnetcore controller work, simply change services.AddControllers(); to services.AddControllers().AddOData(options => options.EnableQueryFeatures()) // Note that this need Microsoft.AspNetCore.OData nuget package to be installed [ApiController] [Route("api/[controller]/[action]")] public class ProductsController : ControllerBase { private static readonly Random _random = new Random(); private static readonly ProductDto[] _products = Enumerable.Range(1, 500_000) .Select(i => new ProductDto { Id = i, Name = Guid.NewGuid().ToString("N"), Price = _random.Next(1, 100) }) .ToArray(); [HttpGet] public async Task> GetProducts(ODataQueryOptions odataQuery, CancellationToken cancellationToken) { var query = _products.AsQueryable(); query = (IQueryable)odataQuery.ApplyTo(query, ignoreQueryOptions: AllowedQueryOptions.Top | AllowedQueryOptions.Skip); var totalCount = query.Count(); if (odataQuery.Skip is not null) query = query.Skip(odataQuery.Skip.Value); query = query.Take(odataQuery.Top?.Value ?? 50); return new PagedResult(query.ToArray(), totalCount); } } // ========== Shared code ========== //https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ [JsonSerializable(typeof(PagedResult))] public partial class AppJsonContext : JsonSerializerContext { } public class ProductDto { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } } public class PagedResult { public IList? Items { get; set; } public int TotalCount { get; set; } public PagedResult(IList items, int totalCount) { Items = items; TotalCount = totalCount; } public PagedResult() { } } // ========== Client code ========== BitDataGridLegacy? productsDataGrid; string _odataSampleNameFilter = string.Empty; BitDataGridItemsProvider productsItemsProvider; string ODataSampleNameFilter { get => _odataSampleNameFilter; set { _odataSampleNameFilter = value; _ = productsDataGrid?.RefreshDataAsync(); } } protected override async Task OnInitializedAsync() { productsItemsProvider = async req => { try { // https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview var query = new Dictionary() { { "$top", req.Count ?? 50 }, { "$skip", req.StartIndex } }; if (string.IsNullOrWhiteSpace(_odataSampleNameFilter) is false) { // Use the trimmed value so a whitespace-only entry isn't treated as a real search // term, while still escaping apostrophes to keep the OData string literal valid. var escapedFilter = _odataSampleNameFilter.Trim().Replace("'", "''"); query.Add("$filter", $"contains(Name,'{escapedFilter}')"); } if (req.GetSortByProperties().Any()) { query.Add("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridLegacySortDirection.Ascending ? "asc" : "desc")}"))); } var url = NavManager.GetUriWithQueryParameters("api/Products/GetProducts", query); var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.PagedResultProductDto, req.CancellationToken); return BitDataGridLegacyItemsProviderResult.From(data!.Items, (int)data!.TotalCount); } catch (OperationCanceledException) when (req.CancellationToken.IsCancellationRequested) { throw; // a rapid refresh superseded this request; let cancellation flow through } catch { return BitDataGridLegacyItemsProviderResult.From(new List { }, 0); } }; } ``` \n**LoadingTemplate**: ```razor @using System.Text.Json; @using System.Text.Json.Serialization; @inject HttpClient HttpClient @inject NavigationManager NavManager
Loading items...
@(state.CurrentPageIndex + 1) / @(state.LastPageIndex + 1) ``` ```csharp // ========== Server code ========== // To make following aspnetcore controller work, simply change services.AddControllers(); to services.AddControllers().AddOData(options => options.EnableQueryFeatures()) // Note that this need Microsoft.AspNetCore.OData nuget package to be installed [ApiController] [Route("api/[controller]/[action]")] public class ProductsController : ControllerBase { private static readonly Random _random = new Random(); private static readonly ProductDto[] _products = Enumerable.Range(1, 500_000) .Select(i => new ProductDto { Id = i, Name = Guid.NewGuid().ToString("N"), Price = _random.Next(1, 100) }) .ToArray(); [HttpGet] public async Task> GetProducts(ODataQueryOptions odataQuery, CancellationToken cancellationToken) { var query = _products.AsQueryable(); query = (IQueryable)odataQuery.ApplyTo(query, ignoreQueryOptions: AllowedQueryOptions.Top | AllowedQueryOptions.Skip); var totalCount = query.Count(); if (odataQuery.Skip is not null) { query = query.Skip(odataQuery.Skip.Value); } query = query.Take(odataQuery.Top?.Value ?? 50); return new PagedResult(query.ToArray(), totalCount); } } // ========== Shared code ========== //https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ [JsonSerializable(typeof(PagedResult))] public partial class AppJsonContext : JsonSerializerContext { } public class ProductDto { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } } public class PagedResult { public IList? Items { get; set; } public int TotalCount { get; set; } public PagedResult(IList items, int totalCount) { Items = items; TotalCount = totalCount; } public PagedResult() { } } // ========== Client code ========== BitDataGridLegacy? productsDataGrid; BitDataGridItemsProvider productsItemsProvider; BitDataGridLegacyPaginationState pagination = new() { ItemsPerPage = 7 }; protected override async Task OnInitializedAsync() { productsItemsProvider = async req => { try { // https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview var query = new Dictionary() { { "$top", req.Count ?? 50 }, { "$skip", req.StartIndex } }; if (req.GetSortByProperties().Any()) { query.Add("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridLegacySortDirection.Ascending ? "asc" : "desc")}"))); } var url = NavManager.GetUriWithQueryParameters("api/Products/GetProducts", query); var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.PagedResultProductDto, req.CancellationToken); return BitDataGridLegacyItemsProviderResult.From(data!.Items, (int)data!.TotalCount); } catch (OperationCanceledException) when (req.CancellationToken.IsCancellationRequested) { throw; // a rapid refresh superseded this request; let cancellation flow through } catch { return BitDataGridLegacyItemsProviderResult.From(new List { }, 0); } }; } ``` \n**Responsive**: ```razor
``` ```csharp private IQueryable allCountries; private BitDataGridLegacyPaginationState pagination = new() { ItemsPerPage = 7 }; protected override async Task OnInitializedAsync() { allCountries = _countries.AsQueryable(); } private static readonly CountryModel[] _countries = [ new CountryModel { Code = "AR", Name = "Argentina", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "AM", Name = "Armenia", Medals = new MedalsModel { Gold = 0, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "AU", Name = "Australia", Medals = new MedalsModel { Gold = 17, Silver = 7, Bronze = 22 } }, new CountryModel { Code = "AT", Name = "Austria", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "AZ", Name = "Azerbaijan", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 4 } }, new CountryModel { Code = "BS", Name = "Bahamas", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BH", Name = "Bahrain", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "BY", Name = "Belarus", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 3 } }, new CountryModel { Code = "BE", Name = "Belgium", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "BM", Name = "Bermuda", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BW", Name = "Botswana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "BR", Name = "Brazil", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 8 } }, new CountryModel { Code = "BF", Name = "Burkina Faso", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "CA", Name = "Canada", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 11 } }, new CountryModel { Code = "TW", Name = "Chinese Taipei", Medals = new MedalsModel { Gold = 2, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "CO", Name = "Colombia", Medals = new MedalsModel { Gold = 0, Silver = 4, Bronze = 1 } }, new CountryModel { Code = "CI", Name = "Côte d'Ivoire", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HR", Name = "Croatia", Medals = new MedalsModel { Gold = 3, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "CU", Name = "Cuba", Medals = new MedalsModel { Gold = 7, Silver = 3, Bronze = 5 } }, new CountryModel { Code = "CZ", Name = "Czech Republic", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 3 } }, new CountryModel { Code = "DK", Name = "Denmark", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 4 } }, new CountryModel { Code = "DO", Name = "Dominican Republic", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "EC", Name = "Ecuador", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "EE", Name = "Estonia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "ET", Name = "Ethiopia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "FJ", Name = "Fiji", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "FI", Name = "Finland", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "FR", Name = "France", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 11 } }, new CountryModel { Code = "GE", Name = "Georgia", Medals = new MedalsModel { Gold = 2, Silver = 5, Bronze = 1 } }, new CountryModel { Code = "DE", Name = "Germany", Medals = new MedalsModel { Gold = 10, Silver = 11, Bronze = 16 } }, new CountryModel { Code = "GH", Name = "Ghana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "GB", Name = "Great Britain", Medals = new MedalsModel { Gold = 22, Silver = 21, Bronze = 22 } }, new CountryModel { Code = "GR", Name = "Greece", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "GD", Name = "Grenada", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HK", Name = "Hong Kong, China", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 3 } }, new CountryModel { Code = "HU", Name = "Hungary", Medals = new MedalsModel { Gold = 6, Silver = 7, Bronze = 7 } }, new CountryModel { Code = "ID", Name = "Indonesia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "IE", Name = "Ireland", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IR", Name = "Iran", Medals = new MedalsModel { Gold = 3, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "IL", Name = "Israel", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IT", Name = "Italy", Medals = new MedalsModel { Gold = 10, Silver = 10, Bronze = 20 } }, new CountryModel { Code = "JM", Name = "Jamaica", Medals = new MedalsModel { Gold = 4, Silver = 1, Bronze = 4 } }, new CountryModel { Code = "JO", Name = "Jordan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "KZ", Name = "Kazakhstan", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 8 } }, new CountryModel { Code = "KE", Name = "Kenya", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 2 } }, new CountryModel { Code = "XK", Name = "Kosovo", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "KW", Name = "Kuwait", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LV", Name = "Latvia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LT", Name = "Lithuania", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "MY", Name = "Malaysia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "MX", Name = "Mexico", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 4 } }, new CountryModel { Code = "MA", Name = "Morocco", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "NA", Name = "Namibia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NL", Name = "Netherlands", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 14 } }, new CountryModel { Code = "NZ", Name = "New Zealand", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 7 } }, new CountryModel { Code = "MK", Name = "North Macedonia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NO", Name = "Norway", Medals = new MedalsModel { Gold = 4, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "PH", Name = "Philippines", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "PL", Name = "Poland", Medals = new MedalsModel { Gold = 4, Silver = 5, Bronze = 5 } }, new CountryModel { Code = "PT", Name = "Portugal", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "PR", Name = "Puerto Rico", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "QA", Name = "Qatar", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "KR", Name = "Republic of Korea", Medals = new MedalsModel { Gold = 6, Silver = 4, Bronze = 10 } }, new CountryModel { Code = "MD", Name = "Republic of Moldova", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "RO", Name = "Romania", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, new CountryModel { Code = "SM", Name = "San Marino", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "SA", Name = "Saudi Arabia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "RS", Name = "Serbia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "SK", Name = "Slovakia", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "SI", Name = "Slovenia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "ZA", Name = "South Africa", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 0 } }, new CountryModel { Code = "ES", Name = "Spain", Medals = new MedalsModel { Gold = 3, Silver = 8, Bronze = 6 } }, new CountryModel { Code = "SE", Name = "Sweden", Medals = new MedalsModel { Gold = 3, Silver = 6, Bronze = 0 } }, new CountryModel { Code = "CH", Name = "Switzerland", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "SY", Name = "Syrian Arab Republic", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TH", Name = "Thailand", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TR", Name = "Turkey", Medals = new MedalsModel { Gold = 2, Silver = 2, Bronze = 9 } }, new CountryModel { Code = "TM", Name = "Turkmenistan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "UA", Name = "Ukraine", Medals = new MedalsModel { Gold = 1, Silver = 6, Bronze = 12 } }, new CountryModel { Code = "US", Name = "United States of America", Medals = new MedalsModel { Gold = 39, Silver = 41, Bronze = 33 } }, new CountryModel { Code = "UZ", Name = "Uzbekistan", Medals = new MedalsModel { Gold = 3, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "VE", Name = "Venezuela", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, ]; public class CountryModel { public string Code { get; set; } public string Name { get; set; } public MedalsModel Medals { get; set; } } public class MedalsModel { public int Gold { get; set; } public int Silver { get; set; } public int Bronze { get; set; } public int Total => Gold + Silver + Bronze; } ``` \n**RowTemplate**: ```razor
@args.OriginalRow @if (expandedRowTemplateCodes.Contains(args.RowItem.Code)) {
Additional data: Code: [@args.RowItem.Code] - Gold: [@args.RowItem.Medals.Gold], Silver: [@args.RowItem.Medals.Silver], Bronze: [@args.RowItem.Medals.Bronze] (Total: @args.RowItem.Medals.Total)
}
``` ```csharp private IQueryable allCountries; private BitDataGridLegacyPaginationState pagination = new() { ItemsPerPage = 7 }; protected override async Task OnInitializedAsync() { allCountries = _countries.AsQueryable(); } private HashSet expandedRowTemplateCodes = []; private void ToggleRowRendererExpand(string code) { if (expandedRowTemplateCodes.Remove(code)) return; expandedRowTemplateCodes.Add(code); } private static readonly CountryModel[] _countries = [ new CountryModel { Code = "AR", Name = "Argentina", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "AM", Name = "Armenia", Medals = new MedalsModel { Gold = 0, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "AU", Name = "Australia", Medals = new MedalsModel { Gold = 17, Silver = 7, Bronze = 22 } }, new CountryModel { Code = "AT", Name = "Austria", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "AZ", Name = "Azerbaijan", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 4 } }, new CountryModel { Code = "BS", Name = "Bahamas", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BH", Name = "Bahrain", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "BY", Name = "Belarus", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 3 } }, new CountryModel { Code = "BE", Name = "Belgium", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "BM", Name = "Bermuda", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "BW", Name = "Botswana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "BR", Name = "Brazil", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 8 } }, new CountryModel { Code = "BF", Name = "Burkina Faso", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "CA", Name = "Canada", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 11 } }, new CountryModel { Code = "TW", Name = "Chinese Taipei", Medals = new MedalsModel { Gold = 2, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "CO", Name = "Colombia", Medals = new MedalsModel { Gold = 0, Silver = 4, Bronze = 1 } }, new CountryModel { Code = "CI", Name = "Côte d'Ivoire", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HR", Name = "Croatia", Medals = new MedalsModel { Gold = 3, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "CU", Name = "Cuba", Medals = new MedalsModel { Gold = 7, Silver = 3, Bronze = 5 } }, new CountryModel { Code = "CZ", Name = "Czech Republic", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 3 } }, new CountryModel { Code = "DK", Name = "Denmark", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 4 } }, new CountryModel { Code = "DO", Name = "Dominican Republic", Medals = new MedalsModel { Gold = 0, Silver = 3, Bronze = 2 } }, new CountryModel { Code = "EC", Name = "Ecuador", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "EE", Name = "Estonia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "ET", Name = "Ethiopia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "FJ", Name = "Fiji", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "FI", Name = "Finland", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "FR", Name = "France", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 11 } }, new CountryModel { Code = "GE", Name = "Georgia", Medals = new MedalsModel { Gold = 2, Silver = 5, Bronze = 1 } }, new CountryModel { Code = "DE", Name = "Germany", Medals = new MedalsModel { Gold = 10, Silver = 11, Bronze = 16 } }, new CountryModel { Code = "GH", Name = "Ghana", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "GB", Name = "Great Britain", Medals = new MedalsModel { Gold = 22, Silver = 21, Bronze = 22 } }, new CountryModel { Code = "GR", Name = "Greece", Medals = new MedalsModel { Gold = 2, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "GD", Name = "Grenada", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "HK", Name = "Hong Kong, China", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 3 } }, new CountryModel { Code = "HU", Name = "Hungary", Medals = new MedalsModel { Gold = 6, Silver = 7, Bronze = 7 } }, new CountryModel { Code = "ID", Name = "Indonesia", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 3 } }, new CountryModel { Code = "IE", Name = "Ireland", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IR", Name = "Iran", Medals = new MedalsModel { Gold = 3, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "IL", Name = "Israel", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "IT", Name = "Italy", Medals = new MedalsModel { Gold = 10, Silver = 10, Bronze = 20 } }, new CountryModel { Code = "JM", Name = "Jamaica", Medals = new MedalsModel { Gold = 4, Silver = 1, Bronze = 4 } }, new CountryModel { Code = "JO", Name = "Jordan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "KZ", Name = "Kazakhstan", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 8 } }, new CountryModel { Code = "KE", Name = "Kenya", Medals = new MedalsModel { Gold = 4, Silver = 4, Bronze = 2 } }, new CountryModel { Code = "XK", Name = "Kosovo", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "KW", Name = "Kuwait", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LV", Name = "Latvia", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "LT", Name = "Lithuania", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "MY", Name = "Malaysia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "MX", Name = "Mexico", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 4 } }, new CountryModel { Code = "MA", Name = "Morocco", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "NA", Name = "Namibia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NL", Name = "Netherlands", Medals = new MedalsModel { Gold = 10, Silver = 12, Bronze = 14 } }, new CountryModel { Code = "NZ", Name = "New Zealand", Medals = new MedalsModel { Gold = 7, Silver = 6, Bronze = 7 } }, new CountryModel { Code = "MK", Name = "North Macedonia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "NO", Name = "Norway", Medals = new MedalsModel { Gold = 4, Silver = 2, Bronze = 2 } }, new CountryModel { Code = "PH", Name = "Philippines", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "PL", Name = "Poland", Medals = new MedalsModel { Gold = 4, Silver = 5, Bronze = 5 } }, new CountryModel { Code = "PT", Name = "Portugal", Medals = new MedalsModel { Gold = 1, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "PR", Name = "Puerto Rico", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 0 } }, new CountryModel { Code = "QA", Name = "Qatar", Medals = new MedalsModel { Gold = 2, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "KR", Name = "Republic of Korea", Medals = new MedalsModel { Gold = 6, Silver = 4, Bronze = 10 } }, new CountryModel { Code = "MD", Name = "Republic of Moldova", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "RO", Name = "Romania", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, new CountryModel { Code = "SM", Name = "San Marino", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 2 } }, new CountryModel { Code = "SA", Name = "Saudi Arabia", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "RS", Name = "Serbia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 5 } }, new CountryModel { Code = "SK", Name = "Slovakia", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 1 } }, new CountryModel { Code = "SI", Name = "Slovenia", Medals = new MedalsModel { Gold = 3, Silver = 1, Bronze = 1 } }, new CountryModel { Code = "ZA", Name = "South Africa", Medals = new MedalsModel { Gold = 1, Silver = 2, Bronze = 0 } }, new CountryModel { Code = "ES", Name = "Spain", Medals = new MedalsModel { Gold = 3, Silver = 8, Bronze = 6 } }, new CountryModel { Code = "SE", Name = "Sweden", Medals = new MedalsModel { Gold = 3, Silver = 6, Bronze = 0 } }, new CountryModel { Code = "CH", Name = "Switzerland", Medals = new MedalsModel { Gold = 3, Silver = 4, Bronze = 6 } }, new CountryModel { Code = "SY", Name = "Syrian Arab Republic", Medals = new MedalsModel { Gold = 0, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TH", Name = "Thailand", Medals = new MedalsModel { Gold = 1, Silver = 0, Bronze = 1 } }, new CountryModel { Code = "TR", Name = "Turkey", Medals = new MedalsModel { Gold = 2, Silver = 2, Bronze = 9 } }, new CountryModel { Code = "TM", Name = "Turkmenistan", Medals = new MedalsModel { Gold = 0, Silver = 1, Bronze = 0 } }, new CountryModel { Code = "UA", Name = "Ukraine", Medals = new MedalsModel { Gold = 1, Silver = 6, Bronze = 12 } }, new CountryModel { Code = "US", Name = "United States of America", Medals = new MedalsModel { Gold = 39, Silver = 41, Bronze = 33 } }, new CountryModel { Code = "UZ", Name = "Uzbekistan", Medals = new MedalsModel { Gold = 3, Silver = 0, Bronze = 2 } }, new CountryModel { Code = "VE", Name = "Venezuela", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, ]; public class CountryModel { public string Code { get; set; } public string Name { get; set; } public MedalsModel Medals { get; set; } } public class MedalsModel { public int Gold { get; set; } public int Silver { get; set; } public int Bronze { get; set; } public int Total => Gold + Silver + Bronze; } ```