【问题标题】:StateHasChanged/this.StateHasChanged doesn't seem to have effect on Blazor ComponentStateHasChanged/this.StateHasChanged 似乎对 Blazor 组件没有影响
【发布时间】:2021-12-24 17:31:43
【问题描述】:

我正在使用 MudBlazor 库开发 .net5 Blazor WebApp。 我正在尝试创建一个显示某些类别和类别页面的导航菜单。但是由于可以添加新类别或添加新类别页面,因此我需要在信息更改时刷新我的组件。在OnInitializedAsync() 中调用该函数时,按预期呈现导航菜单没有问题。但是,在更新它应该呈现的任何信息后再次调用它时,这个函数似乎不再做它应该做的事情,即重新呈现组件。现在,最简单的解决方案可能是我可以简单地刷新整个页面。但这不是我想要的,因为还有其他逻辑需要继续运行而不会受到页面重新加载的干扰。我的 .razor 文件如下所示:

@inject CategoryService categoryService
@inject CategoryPageService categoryPageService

@inherits LayoutComponentBase

<MudText Typo="Typo.h6" Class="px-4" Style="margin-bottom: 10px; margin-top: 10px; text-align:center">Categories</MudText>
<MudDivider />
<MudNavMenu Style="color:white">
@foreach (Category category in NavCategories)
{
    @if(NavCategoryPages.Count > 0)
    {
        @foreach(CategoryPage categoryPage in NavCategoryPages)
        {
            @if(categoryPage.CategoryId == category.Id)
            {
                <MudNavGroup Title=@category.Name>
                    @foreach(CategoryPage categoryPage1 in NavCategoryPages.Where(c => c.CategoryId == category.Id))
                    {
                        <MudNavLink>@categoryPage1.PageName</MudNavLink>
                    }
                </MudNavGroup>
            }
            else
            {
                <MudNavLink>@category.Name</MudNavLink> 
            }
        }
    }
}
</MudNavMenu>

@code
{
    private List<Category> NavCategories = new List<Category>();
    private List<CategoryPage> NavCategoryPages = new List<CategoryPage>();

    protected override async Task OnInitializedAsync()
    {
        await GetCategoriesNav(); //Function that should grab the new information from the database
    }

    public async Task GetCategoriesNav()
    {
        NavCategories = await categoryService.GetCategories();
        NavCategoryPages = await categoryPageService.GetCategoryPages();
        //This delay is to have enough time to view if the StateHasChanged has any effect on first call.
        await Task.Delay(5000);

        StateHasChanged();
    }
}

我已经仔细检查了它们必须显示的所有值,并且它们会相应地显示在调试中。如果您需要任何额外信息,请随时询问。

第一个电话是在:

  • CategorySelector.razor
protected override async Task OnInitializedAsync()
    {
        await GetCategoriesNav();
    }

此调用按应有的方式呈现 NavMenu。之后,唯一一次在其他地方调用它是在我编辑/添加类别时。这是在:

  • 类别管理
//These 2 functions are called via a button.
async Task AddCategory()
    {
        Category thisCategory = new();

        var param = new DialogParameters { ["category"] = thisCategory };

        IDialogReference dialog = DialogService.Show<CategoryDialog>("Add Category", param);

        DialogResult result = await dialog.Result;
        if(!result.Cancelled)
        {
            GetCategories();
            //if a category has succesfully been added, it calls the same method which also gets called in the "OnInitializedAsync()"
            await GetCategoriesNav();
        }
    }


    async Task EditCategory(Category category)
    {
        category = await categoryService.EditCategory(category);

        var param = new DialogParameters { ["category"] = category };

        var dialog = DialogService.Show<CategoryDialog>("Edit Category", param);

        DialogResult result = await dialog.Result;
        if (!result.Cancelled)
        {
            GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
            await GetCategoriesNav();
        }
    }

这里是唯一被调用的外部位置,但 CategoryAdministration 继承自 Category 选择器。

【问题讨论】:

  • 试试InvokeAsync(StateHasChanged) 有时需要异步获取在 UI 线程上发出的 StateHasChanged()。
  • 向我们展示这是如何发生的:引用:“但是在更新它应该呈现的任何信息后再次调用它时”
  • @MisterMagoo 最初在cs protected override async Task OnInitializedAsync() { await GetCategoriesNav(); } 中调用它在应用更改时,我从其他地方调用此函数
  • cs async Task EditCategory(Category category) { category = await categoryService.EditCategory(category); var param = new DialogParameters { ["category"] = category }; var dialog = DialogService.Show&lt;CategoryDialog&gt;("Edit Category", param); DialogResult result = await dialog.Result; if (!result.Cancelled) { GetCategories(); await GetCategoriesNav(); } }
  • 您的描述不够具体,您的图表在登录后。如果您无法编辑您的问题,请找到另一个地方来分享“再次”调用 GetCategoriesNav() 的确切代码,以明确每个调用所在的代码文件。

标签: c# .net blazor mudblazor


【解决方案1】:

我假设您有一个管理页面 CategoryAdmin.razor,其中包含使用编辑器打开对话框的按钮 - 类别对话框。

在该页面中,您有一个组件 - 我假设名为 NavCategoriesComponent - 显示 NavCategories。

您单击其中一个按钮并编辑/添加一个类别,但在退出对话框时,NavCategories 组件中的列表不会更新。

您还有一个CategoryService,我假设它会获取类别列表。

NavCategoriesComponent 中,您的代码如下所示:

private List<Category> NavCategories = new List<Category>();
private List<CategoryPage> NavCategoryPages = new List<CategoryPage>();

//OnInit code
       NavCategories = await categoryService.GetCategories();
        NavCategoryPages = await categoryPageService.GetCategoryPages();
        //not required
        await Task.Delay(5000);

然后在您的主组件中调用以下代码进行添加/编辑:

            GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
            await GetCategoriesNav();

那么您希望第二次调用更新哪个列表? NavCategoriesComponent 中的列表是完全独立的。编辑后调用 GetCategories() 不会更新 NavCategoriesComponent 中的列表。这只发生在您重新加载页面时。 OnInitializedAsync 顾名思义只运行一次。

如果这是您的基本情况,那么:

  1. 您的List&lt;CategoryList&lt;CategoryPage&gt; 列表需要位于CategoryService。现在只有一个版本的真相。
  2. 当您需要填写该列表时,请致电 await categoryService.GetCategories() 获取该列表。
  3. 直接使用NavCategoriesComponent中的列表。
  4. eventRecordListChanged 添加到CategoryService
  5. NavCategoriesComponent 中为该事件注册一个事件处理程序,并在该事件上调用StateHasChaged
  6. 每当您从模式对话框中“创建/更新/删除”时,更新CategoryService 列表并触发RecordListChanged 事件。

您永远不应该手动调用OnInitializedAsync,并且您应该很少需要调用StateHasChanged

此 Github 存储库包含一个解决方案,该解决方案在旧的 Blazor WeatherReport 应用程序中演示了上述原则 - Blazr.Demo.DBNotification

【讨论】:

  • 我会试试这个。我以前做过大致相同的事情,但完全一样。
  • 经过一番折腾,终于搞定了,非常感谢!
猜你喜欢
  • 2015-10-31
  • 2019-02-16
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
  • 2021-11-01
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多