Skip to content

Make QuickGrid more inheritance friendly (second try) #63326

@wolfgangschneider

Description

@wolfgangschneider

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

I am try to Inherited a component from QickGrid to archive classic RowSelect (blue TR background after Row click).

I suggest this feature some years ago , see #45182

Describe the solution you'd like

Change some private Modifier to protected to help people to Inherit there own Grid from QickGrid. Or find some other way to override RenderRow and so on.

Additional context

currently I use the (brutal) UnsafeAccessor to archive my goal

public static class QuckGridUnsafeAccess<TGridItem> where TGridItem : class
{
    //Access Fields
    [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_currentNonVirtualizedViewItems")]
    public static extern ref ICollection<TGridItem> Get_currentNonVirtualizedViewItems(QuickGrid<TGridItem> instance);
    
    [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_renderNonVirtualizedRows")]
    public static extern ref RenderFragment Get_renderNonVirtualizedRows(QuickGrid<TGridItem> instance);

    [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_columns")]
    public static extern ref List<ColumnBase<TGridItem>> Get_columns(QuickGrid<TGridItem> instance);

    [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_virtualizeComponent")]
    public static extern ref Virtualize<(int, TGridItem)>? Get_virtualizeComponent(QuickGrid<TGridItem> instance);

    //Access Methods
    [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "RenderPlaceholderRow")]
    public static extern void Call_RenderPlaceholderRow(QuickGrid<TGridItem> instance,RenderTreeBuilder builder,PlaceholderContext placeholderContext);

    [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CellContent")]
    public static extern void Call_CellContent(ColumnBase<TGridItem> instance, RenderTreeBuilder builder, TGridItem item);

    [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "ProvideVirtualizedItems")]
    public extern static ValueTask<ItemsProviderResult<(int, TGridItem)>> Call_ProvideVirtualizedItemsAsync(QuickGrid<TGridItem> instance, ItemsProviderRequest request);
    public static ItemsProviderDelegate<(int, TGridItem)> Get_UnsafeItemsProviderDelegate(EBQuickGrid<TGridItem> gridInstance)
    {
        return async request =>
        {

            var ret = await Call_ProvideVirtualizedItemsAsync(gridInstance as QuickGrid<TGridItem>, request);
            return ret;
        };
    }

    //Access Static Methods
    [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "ColumnClass")]
    public extern static string? Call_ColumnClass(QuickGrid<TGridItem>? unused, ColumnBase<TGridItem> column);

}

now I can create my own EBQickGrid :QuickGrid

to bend the _renderNonVirtualizedRows RenderFragment

 ref RenderFragment _renderNonVirtualizedRows = ref QuckGridUnsafeAccess<TGridItem>.Get_renderNonVirtualizedRows(this);
 _renderNonVirtualizedRows = RenderRowsEBQickGrid;

And render the row with an OnClick eventhandler and optional with select attribute

 private void RenderRowsEBQickGrid(RenderTreeBuilder __builder)
 {
     @if (VirtualizeEBGrid)
     {
    
         RenderVirtualizedRowsEBQickGrid(__builder);
     }
     else
     {
         RenderNonVirtualizedRowsEBQickGrid(__builder);
     }
 }
 private void RenderVirtualizedRowsEBQickGrid(RenderTreeBuilder __builder)
 {
    
     <Virtualize @ref="QuckGridUnsafeAccess<TGridItem>.Get_virtualizeComponent(this)"
             TItem="(int RowIndex, TGridItem Data)"
             ItemSize="@ItemSize"
             OverscanCount="@OverscanCount"
             ItemsProvider="QuckGridUnsafeAccess<TGridItem>.Get_UnsafeItemsProviderDelegate(this)"
             ItemContent="@(item => builder => RenderRowEBQuckGrid(builder, item.RowIndex, item.Data))"
             // Placeholder="@(placeholderContext => builder => QuckGridUnsafeAccess<TGridItem>.Call_RenderPlaceholderRow(this,builder, placeholderContext))" 
             
             />

 }


 private void RenderNonVirtualizedRowsEBQickGrid(RenderTreeBuilder __builder)
 {
     var initialRowIndex = 2; // aria-rowindex is 1-based, plus the first row is the header
     var rowIndex = initialRowIndex;


     var _currentNonVirtualizedViewItems = QuckGridUnsafeAccess<TGridItem>.Get_currentNonVirtualizedViewItems(this );

     foreach (var item in _currentNonVirtualizedViewItems)
     {
         RenderRowEBQuckGrid(__builder, rowIndex++, item);
     }

     // When pagination is enabled, by default ensure we render the exact number of expected rows per page,
     // even if there aren't enough data items. This avoids the layout jumping on the last page.
     // Consider making this optional.
     if (Pagination is not null)
     {
         var _columns = QuckGridUnsafeAccess<TGridItem>.Get_columns(this);
         while (rowIndex++ < initialRowIndex + Pagination.ItemsPerPage)
         {
             <tr>
                 @foreach (var col in _columns)
                 {
                     var cssClass = QuckGridUnsafeAccess<TGridItem>.Call_ColumnClass(null, col);
                     <td class="@cssClass" @key="@col"></td>
                 }
             </tr>
         }
     }
 }

 protected void RenderRowEBQuckGrid(RenderTreeBuilder __builder, int rowIndex, TGridItem item)
 {
     bool selected = ShouldSelect(item);
     var rowClass = RowClass?.Invoke(item);
     var _columns = QuckGridUnsafeAccess<TGridItem>.Get_columns(this );

     <tr @key="@(ItemKey(item))"  aria-rowindex="@rowIndex" selected="@selected" @onclick="() => OnClickAsync(item!, rowIndex)">
         @foreach (var col in _columns)
         {
             var cssClass = QuckGridUnsafeAccess<TGridItem>.Call_ColumnClass(null, col);

             <td class="@cssClass" @key="@col">
             @{
                 QuckGridUnsafeAccess<TGridItem>.Call_CellContent(col , __builder, item);
             }
             </td>
         }
     </tr>
 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions