blazor.net-8.0mudblazor

Clicked row indication stops working as soon as a callback is being invoked by RowClickEvent in MudBlazor table


While trying to implement and adapt this MudBlazor table example here: MudBlazor example: Click Event and display for selected Row, I invoke a callback from RowClickEvent:

private void RowClickEvent(TableRowClickEventArgs<DriveFile> _tableRowClickEventArgs)
    {
        // verify that the delegate associated with this event dispatcher is non-null
        if (OnDriveFileSelected.HasDelegate)
        {
            if (_tableRowClickEventArgs.Item != null) OnDriveFileSelected.InvokeAsync(_tableRowClickEventArgs.Item.Id);
        }
    }

as soon as OnDriveFileSelected.InvokeAsync is being called, the table doesn't properly indicate the selected row any more. It's supposed to change the background color of the selected row, but it only changes the row's background color once I unselect the row by clicking it again. Once OnDriveFileSelected.InvokeAsync is being removed, the background indicator works as expected. The callback is being called, it's the background color indication that doesn't work.

Here's my full code, excluding using statements:

<style>
    .selected {
        background-color: #1E88E5 !important;
    }
    .selected > td {
        color: white !important;
    }
    .selected > td .mud-input {
        color: white !important;
    }
</style>


<MudTable T="DriveFile" Items="@Elements"Dense="false" Hover="true" Bordered="false" Striped="true" FixedHeader="true"
          FixedFooter="true" RowClass="cursor-pointer"  Breakpoint="Breakpoint.Sm"
          OnRowClick="RowClickEvent"
          Filter="new Func<DriveFile, bool>(FilterFunc1)"
          RowClassFunc="@SelectedRowClassFunc"
          @bind-SelectedItem="selectedItem1"
          @ref="mudTable">
    <ToolBarContent>
        <!-- <MudText Typo="Typo.h6">DriveFiles</MudText> -->
        <MudSpacer />
        <MudTextField @bind-Value="searchString1" Placeholder="Search" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
    </ToolBarContent>
    <HeaderContent>
        <MudTh>File Name</MudTh>
        <MudTh>File Size</MudTh>
        <MudTh>Upload Date</MudTh>
    </HeaderContent>
    <RowTemplate>
        <MudTd DataLabel="FileName">@context.FileName</MudTd>
        <MudTd DataLabel="FileSize">@context.FileSize</MudTd>
        <MudTd DataLabel="UploadTimestamp">@context.UploadTimestamp</MudTd>
    </RowTemplate>
</MudTable>


@code {
    
        
    [Parameter]
    public EventCallback<Guid> OnDriveFileSelected { get; set; } 
    
    [Parameter]
    public string FolderOrLabelToRetrieve { get; set; }
    
    private DriveFile selectedItem1 = null;
    private string searchString1 = "";
    private bool FilterFunc1(DriveFile _DriveFile) => FilterFunc(_DriveFile, searchString1);

    private bool FilterFunc(DriveFile _DriveFile, string searchString)
    {
        if (string.IsNullOrWhiteSpace(searchString)) return true;
        
        
        if (_DriveFile.FileName.Contains(searchString, StringComparison.OrdinalIgnoreCase))
            return true;
        
        return false;
    }
    
    
    
    private int selectedRowNumber = -1;
    private MudTable<DriveFile> mudTable;
    private List<string> clickedEvents = new();
    private IEnumerable<DriveFile> Elements;

    protected override Task OnInitializedAsync()
    {
        Elements = DatabaseAbstractionLayer.GetLabelOrFolderDriveFiles("Files").ToList();
        return base.OnInitializedAsync();
    }

    private void RowClickEvent(TableRowClickEventArgs<DriveFile> _tableRowClickEventArgs)
    {
        // verify that the delegate associated with this event dispatcher is non-null
        if (OnDriveFileSelected.HasDelegate)
        {
            // if (_tableRowClickEventArgs.Item != null) OnDriveFileSelected.InvokeAsync(_tableRowClickEventArgs.Item.Id);
        }
    }

    private string SelectedRowClassFunc(DriveFile element, int rowNumber)
    {
        if (selectedRowNumber == rowNumber)
        {
            selectedRowNumber = -1;
            clickedEvents.Add("Selected Row: None");
            return string.Empty;
        }
        else if (mudTable.SelectedItem != null && mudTable.SelectedItem.Equals(element))
        {
            selectedRowNumber = rowNumber;
            clickedEvents.Add($"Selected Row: {rowNumber}");
            return "selected";
        }
        else
        {
            return string.Empty;
        }
    }

Since I'm using the table in a reusable component and other components need to react to the user selecting a row, I'd like this callback to work.

Changing RowClickEvent to an async method or async Task and awaiting or not awaiting the result of OnDriveFileSelected.InvokeAsync(_tableRowClickEventArgs.Item.Id); doesn't get the row indication to work.

Would anybody please know how I can get both the callback and the color indication to work? Thank you so much!


Solution

  • Change your SelectedRowClassFunc method like below can fix the issue.

    private string SelectedRowClassFunc(DriveFile element, int rowNumber)
    {
        // if (selectedRowNumber == rowNumber)
        // {
        //     selectedRowNumber = -1;
        //     clickedEvents.Add("Selected Row: None");
        //     return string.Empty;
        // }
        // else if (mudTable.SelectedItem != null && mudTable.SelectedItem.Equals(element))
        // {
        //     selectedRowNumber = rowNumber;
        //     clickedEvents.Add($"Selected Row: {rowNumber}");
        //     return "selected";
        // }
        // else
        // {
        //     return string.Empty;
        // }
        return selectedItem1 != null && selectedItem1.Equals(element) ? "selected" : string.Empty;
    }
    

    Test Result

    enter image description here

    enter image description here

    My Test Code

    ParentComponent.razor

    @page "/parent"
    @using MudBlazor
    
    <h3>Selected File ID: @SelectedFileId</h3>
    
    <DriveFileTable OnDriveFileSelected="HandleFileSelected" />
    
    @code {
        private Guid SelectedFileId;
        
        private async Task HandleFileSelected(Guid fileId)
        {
            SelectedFileId = fileId;
            Console.WriteLine($"Selected file ID: {fileId}");
        }
    }
    

    DriveFileTable.razor

    @page "/drive-files"
    @using MudBlazor
    @using BlazorApp1.Data
    
    <style>
        .selected {
            background-color: #1E88E5 !important;
        }
        .selected > td {
            color: white !important;
        }
        .selected > td .mud-input {
            color: white !important;
        }
    </style>
    
    
    <MudTable T="DriveFile" Items="@Elements"Dense="false" Hover="true" Bordered="false" Striped="true" FixedHeader="true"
              FixedFooter="true" RowClass="cursor-pointer"  Breakpoint="Breakpoint.Sm"
              OnRowClick="RowClickEvent"
              Filter="new Func<DriveFile, bool>(FilterFunc1)"
              RowClassFunc="@SelectedRowClassFunc"
              @bind-SelectedItem="selectedItem1"
              @ref="mudTable">
        <ToolBarContent>
            <!-- <MudText Typo="Typo.h6">DriveFiles</MudText> -->
            <MudSpacer />
            <MudTextField @bind-Value="searchString1" Placeholder="Search" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
        </ToolBarContent>
        <HeaderContent>
            <MudTh>File Name</MudTh>
            <MudTh>File Size</MudTh>
            <MudTh>Upload Date</MudTh>
        </HeaderContent>
        <RowTemplate>
            <MudTd DataLabel="FileName">@context.FileName</MudTd>
            <MudTd DataLabel="FileSize">@context.FileSize</MudTd>
            <MudTd DataLabel="UploadTimestamp">@context.UploadTimestamp</MudTd>
        </RowTemplate>
    </MudTable>
    
    
    @code {
    
    
        [Parameter]
        public EventCallback<Guid> OnDriveFileSelected { get; set; } 
    
        [Parameter]
        public string FolderOrLabelToRetrieve { get; set; }
    
        private DriveFile selectedItem1 = null;
        private string searchString1 = "";
        private bool FilterFunc1(DriveFile _DriveFile) => FilterFunc(_DriveFile, searchString1);
    
        private bool FilterFunc(DriveFile _DriveFile, string searchString)
        {
            if (string.IsNullOrWhiteSpace(searchString)) return true;
    
    
            if (_DriveFile.FileName.Contains(searchString, StringComparison.OrdinalIgnoreCase))
                return true;
    
            return false;
        }
    
    
    
        private int selectedRowNumber = -1;
        private MudTable<DriveFile> mudTable;
        private List<string> clickedEvents = new();
        private IEnumerable<DriveFile> Elements;
    
        protected override Task OnInitializedAsync()
        {
            Elements = new List<DriveFile>
            {
                new DriveFile { Id = Guid.NewGuid(), FileName = "Document1.docx", FileSize = 1024, UploadTimestamp = DateTime.Now.AddDays(-1) },
                new DriveFile { Id = Guid.NewGuid(), FileName = "Image1.jpg", FileSize = 2048, UploadTimestamp = DateTime.Now.AddDays(-2) },
                new DriveFile { Id = Guid.NewGuid(), FileName = "Spreadsheet1.xlsx", FileSize = 4096, UploadTimestamp = DateTime.Now.AddDays(-3) }
            };
            return base.OnInitializedAsync();
        }
    
        private async Task RowClickEvent(TableRowClickEventArgs<DriveFile> _tableRowClickEventArgs)
        {
            selectedItem1 = _tableRowClickEventArgs.Item;
    
            StateHasChanged();
    
            if (OnDriveFileSelected.HasDelegate && _tableRowClickEventArgs.Item != null)
            {
                await OnDriveFileSelected.InvokeAsync(_tableRowClickEventArgs.Item.Id);
            }
    
            StateHasChanged();
        }
    
        private string SelectedRowClassFunc(DriveFile element, int rowNumber)
        {
            // if (selectedRowNumber == rowNumber)
            // {
            //     selectedRowNumber = -1;
            //     clickedEvents.Add("Selected Row: None");
            //     return string.Empty;
            // }
            // else if (mudTable.SelectedItem != null && mudTable.SelectedItem.Equals(element))
            // {
            //     selectedRowNumber = rowNumber;
            //     clickedEvents.Add($"Selected Row: {rowNumber}");
            //     return "selected";
            // }
            // else
            // {
            //     return string.Empty;
            // }
            return selectedItem1 != null && selectedItem1.Equals(element) ? "selected" : string.Empty;
        }
    }