1

This has probably been asked before, but I'm at a loss as to what's going on here: I have a Blazor page that calls a dialog component to edit, insert, delete a record in the database. After either Deleting or Inserting a record (not editing - no need), I want to simply refresh a grid (table) with the new results. So I get a return value from the component when it is closed that is either True or False : True = refresh parent/caller page with the new results, False = do nothing (when just changing a record). The problem is the UI is never updated (even if calling StateHasChanged()), and I understand that won't work as it is only a request to update the GUI, not a forced refresh. What I don't understand is exactly HOW to achieve this goal. MS BOL is confusing as heck and no actual working examples with a razor component. I know how to send data back to the caller - that's not the problem. In fact, that's working perfectly, but the Main page acts like it needs another event (though I want it to refresh automatically), but I'm not sure how to invoke a dummy event to get it to refresh properly. Here's the main/index page code:

    @page "/"
@inject IConfiguration config
@inject DialogService dialog
@inject NotificationService notification

<PageTitle>Memo Master</PageTitle>
<RadzenButton Click="GetMemos" Text="Get Memos" ButtonStyle="ButtonStyle.Primary" ButtonType="ButtonType.Submit" />
<RadzenTextBox @ref="searchBox" Name="SearchPhrase" @bind-Value=@SearchString MaxLength="400" @oninput=@(args => SearchString = args.Value.ToString()) @onkeydown=@Enter />  @*searchString value continually updated for onkeydown to work*@
<RadzenButton Click="() => OpenMemo(0)" Text="New Memo" Icon="add_circle_outline" ButtonStyle="ButtonStyle.Secondary" />

<br />
<br />
@if (FoundMemos != null && busy == false)
{
    <RadzenDataGrid Data="@FoundMemos" TItem="MemoSearch" AllowFiltering="true" AllowSorting="true" AllowColumnResize="true" AllowPaging="true" PageSize=20
                FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" SelectionMode="DataGridSelectionMode.Single" @bind-Value="@SelectedMemos" RowClick="@OnRowClicked">
        <Columns>
            <RadzenDataGridColumn TItem="MemoSearch" Title="Index" Width="70px" Filterable="false" TextAlign="TextAlign.Left">
                <Template Context="m">
                    <RadzenText TextStyle="TextStyle.Caption">@m.Idx.ToString()</RadzenText>
                </Template>
            </RadzenDataGridColumn>
            <RadzenDataGridColumn TItem="MemoSearch" Property="Title" Title="Title">
            </RadzenDataGridColumn>
            <RadzenDataGridColumn TItem="MemoSearch" Title="Modified" Width="140px" TextAlign="TextAlign.Right">
                <Template Context="m">
                    <RadzenText TextStyle="TextStyle.Caption">@m.ModifiedOn.ToString("MM/dd/yyyy hh:mm tt")</RadzenText>
                </Template>
            </RadzenDataGridColumn>
        </Columns>
    </RadzenDataGrid>
}
else
{
    <DisplaySpinner />
}
<br />
<br />
<RadzenButton Click="Reset" Text="Reset" ButtonStyle="ButtonStyle.Secondary" />

@code {
    List<MemoSearch> FoundMemos = new();
    private string SearchString = "";
    private string DBConnStr { get; set; } = "";
    public DB dB = new();
    IList<MemoSearch>? SelectedMemos;
    RadzenTextBox searchBox = new();
    private bool busy;

    async Task OpenMemo(int Idx)
    {
        string DialogTitle = (Idx == 0) ? "Create New Memo" : $"Edit Memo {Idx.xToStr()}";

        bool RefreshResults = await dialog.OpenAsync<MemoDetails>(DialogTitle, new Dictionary<string, object>() { { "Idx", Idx } });
        if (RefreshResults)
        {
            await GetMemos(); //this method is called, but no page refresh 
            StateHasChanged(); //this isn't causing the page to refresh
        }
    }

    protected override async Task OnInitializedAsync() => dB.DBConnStr = config.GetConnectionString("DBConnStr");

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender) await searchBox.Element.FocusAsync(); //NOTE: this is for Radzen "elements"
    }

    public async Task GetMemos()
    {
        busy = true;
        FoundMemos = await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999);
        busy = false;
    }

    public void Reset()
    {
        FoundMemos = new();
        SearchString = "";
    }

    public async void Enter(KeyboardEventArgs e)
    {
        if (e.Code == "Enter" || e.Code == "NumpadEnter" || e.Key == "Enter")
        {
            await GetMemos();
            StateHasChanged();
        }
    }

    async Task OnRowClicked(Radzen.DataGridRowMouseEventArgs<MemoSearch> args)
    {
        if (args != null)
        {
            await OpenMemo(args.Data.Idx);
        }
    }
}

The Details razor component code:

    @inject IConfiguration config
@inject DialogService dialog
@inject NotificationService notification

@if (memo != null)
{
    <RadzenTemplateForm TItem="Memo" Data=@memo Submit=@OnSubmit>
        <p>
            <RadzenLabel Component="Title" Text="Title" />
            <RadzenTextBox id="MemoTitle" Name="Title" @bind-Value=@memo.Title MaxLength="400" />
            <RadzenRequiredValidator Component="Title" Text="Title is required!" />
        </p>
        <p>
            <RadzenLabel Component="Body" Text="Memo" />
            <RadzenTextArea id="MemoBody" Name="Body" @bind-Value=@memo.Body Rows="18" />
        </p>
        <p>
            <RadzenLabel Component="Keywords" Text="Key Words" />
            <RadzenTextBox id="MemoKeywords" Name="Keywords" @bind-Value=@memo.Keywords MaxLength="400" />
        </p>
        <RadzenButton ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Icon="save" Text="Save" BusyText="Saving ..." IsBusy=@busy />
        <RadzenButton ButtonType="ButtonType.Button" ButtonStyle="ButtonStyle.Danger" Icon="delete" Text="Delete" Click="@((args) => DeleteMemo(memo.Idx))" @onclick:stopPropagation="true"></RadzenButton>
        <RadzenButton Text="Close" Click="() => dialog.Close(false)" ButtonStyle="ButtonStyle.Light" />
    </RadzenTemplateForm>
}

@code {
    [Parameter]
    public int Idx { get; set; }
    public DB dB = new();
    Memo? memo;
    bool busy;

    protected override async void OnInitialized()
    {
        dB.DBConnStr = config.GetConnectionString("DBConnStr");
        memo = (Idx == 0) ? new Memo() : await GetMemoByIdx(Idx);
        await InvokeAsync(() => StateHasChanged()).ConfigureAwait(false); //IMPORTANT!!
    }

    public async Task<Memo> GetMemoByIdx(int Idx) => await dB.MemoSelectByIdxAsync(Idx);

    async Task OnSubmit(Memo memo)
    {
        busy = true;
        int Result;
        bool RefreshResults = false;
        if (memo.ModifiedOn == DateTime.MinValue) memo.ModifiedOn = DateTime.Now;
        string NotificationDetailMessage = memo.Idx == 0 ? "New Memo has been created." : $"Memo {memo.Idx} has been saved.";
        Result = await dB.MemoUpsertAsync(memo);
        if (Result < -1)
        {
            notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Error Saving", Detail = "An error saving this record has occured!\n" + dB.LastErrorMsg, Duration = 4000 });
        }
        else
        {
            notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Save Success", Detail = NotificationDetailMessage, Duration = 2000 });
        }
        busy = false;
        RefreshResults = (memo.Idx == 0 && Result >= -1) ? true : false; //send the refresh message only if it's new memo AND it's successful
        dialog.Close(RefreshResults);
    }


    async Task DeleteMemo(int Idx)
    {
        busy = true;
        int Result;
        bool RefreshResults = false;
        var confirmResult = await dialog.Confirm("Are you sure?", "Confirm Memo Deletion");
        if (confirmResult.HasValue && confirmResult.Value)
        {
            Result = await dB.MemoDeleteByIdxAsync(Idx);
            if (Result < -1)
            {
                notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Error Deleting", Detail = "An error deleting this record has occured!\n" + dB.LastErrorMsg, Duration = 4000 });
            }
            else
            {
                notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Deletion Success", Detail = $"Memo {Idx} has been deleted.", Duration = 2000 });
                RefreshResults = true;
            }
        }
        busy = false;
        dialog.Close(RefreshResults);
    }

}

As can be seen, a boolean value is returned (it works) from the dialog call inside the OpenMemo method, and I wish to refresh the UI if it's set to true, which I then call the GetMemos method and call StateHasChanged. I am able to step through the debugger and everything is working fine (FoundMemos has records, including the newly created one or minus a deleted one!), even the markup test is working, yet it doesn't display. Oddly, SOMETIMES when stepping through the code, the page refreshes! I can't figure out what is going on and why this is happening (and more importantly, how to fix it). I've tried the hacky Task.Delay(somenumber) in between the GetMemos call and the StateHasChanged, with no joy. What am I missing?

This is a Server Side Blazor app on DotNet7.0 (for in-house use)


************* New Code - Works except when searchbox has a value in it **

Index.razor:

@page "/"
@inject IConfiguration config
@inject DialogService dialog
@inject NotificationService notification

<PageTitle>Memo Master</PageTitle>
<RadzenButton Click="() => GetMemos()" Text="Get Memos" ButtonStyle="ButtonStyle.Primary" ButtonType="ButtonType.Submit" />
<RadzenTextBox @ref="searchBox" Name="SearchPhrase" @bind-Value=@SearchString MaxLength="400" @oninput=@(args => SearchString = args.Value.ToString()) @onkeydown=@Enter />
<RadzenButton Click="() => OpenMemo(0)" Text="New Memo" Icon="add_circle_outline" ButtonStyle="ButtonStyle.Secondary" />
<br />
<br />
@if (FoundMemos != null && !busy)
{
    <RadzenDataGrid @ref=this.grid Data="@FoundMemos" TItem="MemoSearch" AllowFiltering="true" AllowSorting="true" AllowColumnResize="true" AllowPaging="true" PageSize=20
                FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" SelectionMode="DataGridSelectionMode.Single" @bind-Value="@SelectedMemos" RowClick="@OnRowClicked">
        <Columns>
            <RadzenDataGridColumn TItem="MemoSearch" Title="Index" Width="70px" Filterable="false" TextAlign="TextAlign.Left">
                <Template Context="m">
                    <RadzenText TextStyle="TextStyle.Caption">@m.Idx.ToString()</RadzenText>
                </Template>
            </RadzenDataGridColumn>
            <RadzenDataGridColumn TItem="MemoSearch" Property="Title" Title="Title">
            </RadzenDataGridColumn>
            <RadzenDataGridColumn TItem="MemoSearch" Title="Modified" Width="140px" TextAlign="TextAlign.Right">
                <Template Context="m">
                    <RadzenText TextStyle="TextStyle.Caption">@m.ModifiedOn.ToString("MM/dd/yyyy hh:mm tt")</RadzenText>
                </Template>
            </RadzenDataGridColumn>
        </Columns>
    </RadzenDataGrid>
}
else
{
    <DisplaySpinner />
}
<br />
<br />
<RadzenButton Click="Reset" Text="Reset" ButtonStyle="ButtonStyle.Secondary" />

@code {
    [Parameter]
    public string? SearchString { get; set; }

    List<MemoSearch> FoundMemos = new();
    private string DBConnStr { get; set; } = "";
    public DB dB = new();
    IList<MemoSearch>? SelectedMemos;
    RadzenTextBox? searchBox;
    private bool busy;
    private RadzenDataGrid<MemoSearch>? grid; //reference to grid, so forced reloading can happen - though it doesn't actually work

    async Task OpenMemo(int Idx)
    {
        string DialogTitle = (Idx == 0) ? "Create New Memo" : $"Edit Memo {Idx.xToStr()}";
        object? RefreshResults = await dialog.OpenAsync<MemoDetails>(DialogTitle, new Dictionary<string, object>() { { "Idx", Idx } });
        RefreshResults = (RefreshResults == null) ? false : RefreshResults;
        if (RefreshResults.xToBoo())
        {
            await GetMemos();
        }
        await ReturnFocus();
    }

    protected override async Task OnInitializedAsync()
    {
        dB.DBConnStr = config.GetConnectionString("DBConnStr");
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender) await ReturnFocus();  //NOTE: this is for Radzen "elements"
    }

    public async Task GetMemos()
    {
        busy = true;
        FoundMemos = await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999);   
        busy = false;
    }

    public async Task Reset()
    {
        FoundMemos = new();
        SearchString = "";
        await ReturnFocus();
    }

    public async void Enter(KeyboardEventArgs e)
    {
        if (e.Code == "Enter" || e.Code == "NumpadEnter" || e.Key == "Enter")
        {
            await GetMemos();
            StateHasChanged(); //need to call this here after keypress, lest you get a continual spinner
        }
    }

    async Task OnRowClicked(Radzen.DataGridRowMouseEventArgs<MemoSearch> args)
    {
        if (args != null)
        {
            await OpenMemo(args.Data.Idx);
        }
    }

    async Task ReturnFocus()
    {
        await searchBox.Element.FocusAsync();
    }
}

MemoDetails.razor:

    @inject IConfiguration config
@inject DialogService dialog
@inject NotificationService notification

@if (memo != null)
{
    <RadzenTemplateForm TItem="Memo" Data=@memo Submit=@OnSubmit>
        <p>
            <RadzenLabel Component="Title" Text="Title" />
            <RadzenTextBox id="MemoTitle" Name="Title" @bind-Value=@memo.Title MaxLength="400" />
            <RadzenRequiredValidator Component="Title" Text="Title is required!" />
        </p>
        <p>
            <RadzenLabel Component="Body" Text="Memo" />
            <RadzenTextArea id="MemoBody" Name="Body" @bind-Value=@memo.Body Rows="18" />
        </p>
        <p>
            <RadzenLabel Component="Keywords" Text="Key Words" />
            <RadzenTextBox id="MemoKeywords" Name="Keywords" @bind-Value=@memo.Keywords MaxLength="400" />
        </p>
        <RadzenButton ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Icon="save" Text="Save" BusyText="Saving ..." IsBusy=@busy />
        @if (Idx > 0)
        {
            <RadzenButton ButtonType="ButtonType.Button" ButtonStyle="ButtonStyle.Danger" Icon="delete" Text="Delete" Click="@((args) => DeleteMemo(memo.Idx))" @onclick:stopPropagation="true"></RadzenButton>
        }
        <RadzenButton Text="Close" Click="() => dialog.Close(false)" ButtonStyle="ButtonStyle.Light" />
    </RadzenTemplateForm>
}

@code {
    [Parameter]
    public int Idx { get; set; } = 0;

    public DB dB = new();
    Memo? memo;
    bool busy;

    protected override async void OnInitialized()
    {
        dB.DBConnStr = config.GetConnectionString("DBConnStr");
        memo = (Idx == 0) ? new Memo() : await GetMemoByIdx(Idx);
        await InvokeAsync(() => StateHasChanged()).ConfigureAwait(false); //IMPORTANT!!
    }

    public async Task<Memo> GetMemoByIdx(int Idx) => await dB.MemoSelectByIdxAsync(Idx);

    async Task OnSubmit(Memo memo)
    {
        int Result;
        bool RefreshResults = false;
        if (memo.ModifiedOn == DateTime.MinValue) memo.ModifiedOn = DateTime.Now;
        string NotificationDetailMessage = memo.Idx == 0 ? "New Memo has been created." : $"Memo {memo.Idx} has been saved.";
        busy = true;
        Result = await dB.MemoUpsertAsync(memo);
        if (Result < -1)
        {
            notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Error Saving", Detail = "An error saving this record has occured!\n" + dB.LastErrorMsg, Duration = 4000 });
        }
        else
        {
            notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Save Success", Detail = NotificationDetailMessage, Duration = 2000 });
            RefreshResults = true;
        }
        busy = false;
        dialog.Close(RefreshResults);
    }

    async Task DeleteMemo(int Idx)
    {  
        int Result;
        bool RefreshResults = false;
        var confirmResult = await dialog.Confirm("Are you sure?", "Confirm Memo Deletion");
        if (confirmResult.HasValue && confirmResult.Value)
        {
            busy = true;
            Result = await dB.MemoDeleteByIdxAsync(Idx);
            if (Result < -1)
            {
                notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Error Deleting", Detail = "An error deleting this record has occured!\n" + dB.LastErrorMsg, Duration = 4000 });
            }
            else
            {
                notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Deletion Success", Detail = $"Memo {Idx} has been deleted.", Duration = 2000 });
                RefreshResults = true;
            }
        }
        busy = false;
        dialog.Close(RefreshResults);
    }

}
MC9000
  • 2,076
  • 7
  • 45
  • 80
  • When you return from the dialog are you expecting the Radzen DataGrid to refresh? If so then you probably need to tell it to refresh directly. – MrC aka Shaun Curtis Jan 27 '23 at 09:38
  • Just checked and I think you need to get a reference to it with `@ref` and the call `Load()` at the end of `OpenMenu`. If it works I'll explain why in an answer. – MrC aka Shaun Curtis Jan 27 '23 at 09:42

3 Answers3

0

For this method

public async Task GetMemos()
{
        busy = true;
        FoundMemos = await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999);
        busy = false;
}

Try changing it to this :

public async Task GetMemos()
{
    busy = true;
    FoundMemos.Clear();
    FoundMemos.AddRange(await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999));
    busy = false;
}

You might as well modify other function such as Reset() as well.

    public void Reset()
    {
        FoundMemos.Clear();
        SearchString = "";
    }
Fitri Halim
  • 584
  • 4
  • 11
  • Referrence : https://stackoverflow.com/questions/54135574/c-sharp-clearing-a-list-vs-assigning-a-new-list-to-existing-variable – Fitri Halim Jan 27 '23 at 03:31
  • Thanks. That does make a bit more sense to do (cleaner & probably less memory), but, alas, I have the same problem - no refresh. – MC9000 Jan 27 '23 at 07:01
  • What if you add StateHasChange here? `public async Task GetMemos() { busy = true; FoundMemos.Clear(); StateHasChange(); await Task.Delay(10); FoundMemos.AddRange(await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999)); busy = false; }` – Fitri Halim Jan 27 '23 at 07:18
  • unfortunately, it only works if I step through the debugger (as before). I believe I need to somehow wait for something to be completed. I'm not sure what it's waiting for, but going step by step slowly via the debugger works, real time does not. I'll try upping the delay to a second. – MC9000 Jan 27 '23 at 09:45
  • that failed to work, too (I set it to 20,000 ms - just a big delay, zero refresh). Perhaps there's a bug in Radzen controls that is preventing the refresh. – MC9000 Jan 27 '23 at 09:53
  • I had to switch back to FoundMemos = new(); Using clear does not force a change (reset wasn't working), but that's okay (turns out .Clear actually uses more memory and runs slower!). I'm going to try and remove the Success notifications from the MemoDetails and see if that's doing the blocking – MC9000 Jan 27 '23 at 10:01
  • Delete works (refreshes), but Insert does not (they are using the same dialog!!! ). I'm stumped. – MC9000 Jan 27 '23 at 10:10
0

I believe the problem is here.

    public async Task GetMemos()
    {
        busy = true;
        FoundMemos = await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999);
        busy = false;
    }

busy is declared as false and here it get's chagned to true then back to false. Therefore @if (FoundMemos != null && busy == false) never gets satisfied.

Try putting a await Task.Yield() and/or StateHasChanged after you change the first busy=true. Force Blazor to render these changes.

clamchoda
  • 4,411
  • 2
  • 36
  • 74
  • Agree it should work with a yield as it will give the Renderer processing time to render (and destroy) the block. It's a bit drastic though, when you can just call `Reload` on the Grid! – MrC aka Shaun Curtis Jan 27 '23 at 17:19
  • Funny how this works perfectly when stepping through the debugger (grid updates), but delaying [Task.Delay().Wait()], using StateHasChanged(), and using grid.ReLoad() have absolutely no effect. It looks like Radzen controls have a behind-the-scenes problem (they do not play nice with other controls) and they're all tied together. Rolling my own. 4 days wasted. UGH! – MC9000 Jan 30 '23 at 03:35
0

Here's a demo page to show one grid updating and the other not updating.

Note the one updating is referenced with @ref and the button event calls it's Reload method.

@page "/"
<PageTitle>Index</PageTitle>

<h1>Radzen Grid Demo!</h1>

<div class="m-3 text-end">
    <button class="btn btn-primary" @onclick=OnAddCountry>Add USA</button>
</div>

<h3>UpDating Grid</h3>
<RadzenDataGrid Data="@Countries" TItem="Country" @ref=this.grid >
    <Columns>
        <RadzenDataGridColumn TItem="Country" Property="Name" Title="Name" />
        <RadzenDataGridColumn TItem="Country" Property="Continent" Title="Continent" />
    </Columns>
</RadzenDataGrid>

<h3 class="mt-3" >Not Updating Grid</h3>
<RadzenDataGrid Data="@Countries" TItem="Country">
    <Columns>
        <RadzenDataGridColumn TItem="Country" Property="Name" Title="Name" />
        <RadzenDataGridColumn TItem="Country" Property="Continent" Title="Continent" />
    </Columns>
</RadzenDataGrid>

@code {
    private RadzenDataGrid<Country>? grid;
    private Task OnAddCountry()
    {
        Countries.Add(new() { Name = "USA", Continent = "North America" });
        grid?.Reload();
        return Task.CompletedTask;
    }

    public List<Country> Countries = new()
    {
        new Country { Name="UK", Continent="Europe"},   
        new Country { Name="France", Continent="Europe"},
        new Country { Name="Spain", Continent="Europe"},
        new Country { Name="Portugal", Continent="Europe"},
    };

    public record Country
    {
        public string Name { get; init; } = "Not Set";
        public string Continent { get; init; } = "Not Set";
    }
}

Why?

When a component renders, the Renderer decides which sub-components it needs to call SetParametersAsync on based on whether it considers one or more of their parameters have changed. Normal ComponentBase components will re-render because SetParametersAsync makes one or two calls to StateHasChanged.

More complex components such the Radzen grid don't inherit from ComponentBase and have different more complex mechanisms for re-rendering. They need to be told when their base data set has changed because after the first render they don't re-render when SetParametersAsync is called. They are driven by internal events, such as clicking on a sort column, paging,...

Your Code

Your code will need to look something like this:

    <RadzenDataGrid Data="@FoundMemos" TItem="MemoSearch" AllowFiltering="true" AllowSorting="true" AllowColumnResize="true" AllowPaging="true" PageSize=20
                FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" SelectionMode="DataGridSelectionMode.Single" @bind-Value="@SelectedMemos" RowClick="@OnRowClicked" 
                @ref=this.grid >

//.....

    private RadzenDataGrid<MemoSearch>? grid;


    async Task OpenMemo(int Idx)
    {
        string DialogTitle = (Idx == 0) ? "Create New Memo" : $"Edit Memo {Idx.xToStr()}";

        bool RefreshResults = await dialog.OpenAsync<MemoDetails>(DialogTitle, new Dictionary<string, object>() { { "Idx", Idx } });
        if (RefreshResults)
        {
            await GetMemos(); //this method is called, but no page refresh 
            grid?.Reload();
        }
    }
MrC aka Shaun Curtis
  • 19,075
  • 3
  • 13
  • 31
  • I've already tried this. No joy. It only updates the grid if someone deletes a record. This is because another dialog pops up and says "are you sure?" is the only difference between deleting and adding a record (everything else is identical). So, a user event is fired - that's the only difference. So, the solution is to somehow, emulate a user event - that's what I'm looking into now. This could take a couple days of hair pulling (there's very few devs that work w/Blazor, and this is the first time I've had to depend on 3rd party controls w/no source code). I may roll my own (it's easier) – MC9000 Jan 28 '23 at 22:01
  • 1
    I rolled my own: it's similar to QuickGrid. The code is here to get you started - https://github.com/ShaunCurtis/Blazr.NewDemo/tree/master/src/Libraries/Blazr.UI/Components/BlazrGrid. I don't know what the MudBlazor one is like, but you can see the source. – MrC aka Shaun Curtis Jan 28 '23 at 23:08
  • I figured exactly where the problem is: Basically, the grid does refresh after all transactions (update, delete, insert), however, it only does this when no text is already in the search box. Deleted records are deleted, updates and inserts are reflected immediately (so long as there's no text in the search box). It's weird, but I'm still cracking away, now that I know where to look (a bug in my logic regarding the searchbox). - I'm going to replace it w/a non-radzen box and tweak until it works, then work my way back. – MC9000 Jan 29 '23 at 03:14
  • Best of luck. I have a love/hate relationship with third part component libraries. Initial love quickly followed by hate when they don't quite do what I want and I realise how inefficient they are. In any grid type control, unless you do the paging, sorting and filtering at source (by passing a list request object) they are slow (and inefficient) on larger data sets. – MrC aka Shaun Curtis Jan 29 '23 at 09:46