【问题标题】:Why the Blazor UI component doesn't update after delete event?为什么删除事件后 Blazor UI 组件不更新?
【发布时间】:2023-04-09 08:14:01
【问题描述】:

为什么 Blazor 用户界面 在删除事件后不更新:

我的组件:

<table class="table table-striped">
    <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Example</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var trainingTechnique in TrainingTechniques) {
        <tr>
            <td>@trainingTechnique.Id</td>
            <td>@trainingTechnique.Name</td>
            <td>@trainingTechnique.Example</td>
            <td>
                <button type="button" 
                        class="btn btn-danger" 
                        @onclick="@(async () => await DeleteTechnique(trainingTechnique.Id))">
                    Delete
                </button>

            </td>
        </tr>
        }
    </tbody>
</table>

我的组件代码在后面:

public class TrainingTechniqueViewPageBase : ComponentBase
    {
        public List<TrainingTechniqueView> TrainingTechniques { get; set; }
        [Inject] 
        public ITrainingTechniqueConsumer TrainingTechniqueConsumer { get; set; }

        protected TrainingTechniqueForm TrainingTechniqueForm { get; set; } 
        protected override async Task OnInitializedAsync()
        {
            TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
        }

        public async void TrainingTechniqueForm_OnSave()
        {
            TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
            StateHasChanged();
        }

        protected void AddTrainingTechnique()
        {
            TrainingTechniqueForm.Show();
        }

        protected async Task DeleteTechnique(int id)
        {
           await (TrainingTechniqueConsumer.DeleteTrainingTechnique(id));
            this.StateHasChanged();

        }
    }
}

删除方法:

public async Task DeleteTrainingTechnique(int id)
{
    await _httpClient.DeleteAsync($"training/trainingtechniques/{id}");
}

【问题讨论】:

  • 您的问题(当时)已关闭,因为当时情况完全不同。如果您希望重新打开它,请提供minimal reproducible example
  • 显然您编辑了您的问题以使其正常工作?
  • @Vencovsky 不,删除后 UI DOM 仍然没有重绘,我必须导航出页面并返回更新,我无法识别问题
  • @AnynameDonotcare 能否分享一下这个列表项的get方法。
  • @Ashiquzzaman 我已经用更多代码更新了这个问题

标签: c# asp.net-core asynchronous blazor blazor-server-side


【解决方案1】:

解决方案 1:从源重新加载 TrainingTechniques 列表

private async Task Delete(int id)
{
    await TrainingTechniqueConsumer.DeleteTrainingTechnique(id);
    TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
}

解决方案 2:从列表中删除项目:

<table class="table table-striped">
    <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Example</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var trainingTechnique in TrainingTechniques)
        {
            <tr>
                <td>@trainingTechnique.Id</td>
                <td>@trainingTechnique.Name</td>
                <td>@trainingTechnique.Example</td>
                <td>
                    <button type="button" class="btn btn-danger" @onclick="@(() => DeleteTechnique(trainingTechnique.Id))">Delete</button>
                </td>
            </tr>
        }
    </tbody>
</table>

还有Delete方法:

private async Task Delete(int id)
{
    TrainingTechniques.RemoveAll(x => x.Id == Id);
    await TrainingTechniqueConsumer.DeleteTrainingTechnique(id);
}

【讨论】:

  • 非常感谢;你更喜欢哪种解决方案,我认为第二种更有效,因为没有第二次访问数据库,但是请问如果我进行分页(多页)和排序,这是否会获得正确的索引?
  • 第二个确实会提供更好的用户体验。我已经用 Id 而不是索引删除了 anwens,所以排序和东西绝对没有问题
【解决方案2】:

从列表中删除与 UI 绑定的项目。

protected async Task DeleteTechnique(int id)
{
    await (TrainingTechniqueConsumer.DeleteTrainingTechnique(id));
    TrainingTechniques.Remove(TrainingTechniques.Single(x => x.Id == id));
}

我认为最好将项目传递给自己而不是 Id。例如删除可能是:

protected async Task DeleteTechnique(TrainingTechniqueView corpse)
{
    await (TrainingTechniqueConsumer.DeleteTrainingTechnique(corpse.Id));
    TrainingTechniques.Remove(corpse);
}

【讨论】:

    【解决方案3】:

    我遇到了和你一样的问题和几乎相同的 UI,但我的问题不是将 TrainingTechniques 定义为 List,而是将其定义为 IEnumerable。所以而不是:

    public IEnumerable<TrainingTechniqueView> TrainingTechniques { get; set; }
    

    我改成了:

    public List<TrainingTechniqueView> TrainingTechniques { get; set; }
    

    然后使用@Inktkiller 建议的解决方案之一。

    【讨论】:

      【解决方案4】:

      您正确地删除了后端的项目。
      但为了看到效果,您必须重新加载数据:

      protected async Task DeleteTechnique(int id)
      {
         await (TrainingTechniqueConsumer.DeleteTrainingTechnique(id));
         TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
       //this.StateHasChanged(); -- not necessary
      }
      

      作为替代方案,您可以从已加载的 TrainingTechniques 中删除项目,这是一个小的优化,但您会冒并发错误的风险。

      【讨论】:

      • 啊我刚刚看到Ink Killer已经回答了这个问题。不过,这是核心。
      • 非常感谢,我应该使用锁来避免从列表中同时删除的风险吗?因为我认为如果我有一个大列表,从它中删除而不是获取它将是一个很大的优化再次完整的数据。或者您推荐其他解决方案?
      • “我应该使用锁吗..” - 不,您所有的代码都在同一个线程上运行,不要修复未损坏的部分。
      • “将是一个很大的优化” - 是的,但是以最新的为代价。有多少用户会编辑这些数据?
      • 大约 5-7 个用户
      【解决方案5】:

      下面的代码对我有用-

      TrainingTechnique.razor:

      <table class="table table-striped">
          <thead>
              <tr>
                  <th>Id</th>
                  <th>Name</th>
                  <th>Example</th>
                  <th></th>
              </tr>
          </thead>
          <tbody>
              @foreach (var trainingTechnique in TrainingTechniques)
              {
                  <tr>
                      <td>@trainingTechnique.Id</td>
                      <td>@trainingTechnique.Name</td>
                      <td>@trainingTechnique.Example</td>
                      <td>
                          <button type="button" class="btn btn-danger" @onclick="@(async () => await DeleteTechnique(trainingTechnique.Id))">Delete</button>
      
                      </td>
                  </tr>
              }
          </tbody>
      </table>
      

      组件:

          public class TrainingTechniqueViewPageBase : ComponentBase
          {
              public List<TrainingTechniqueView> TrainingTechniques { get; set; }
              [Inject] 
              public ITrainingTechniqueConsumer TrainingTechniqueConsumer { get; set; }
      
              protected TrainingTechniqueForm TrainingTechniqueForm { get; set; } 
              protected override async Task OnInitializedAsync()
              {
                  TrainingTechniques = await TrainingTechniqueConsumer.GetTechniques().ToListAsync();
              }
      
              public async void TrainingTechniqueForm_OnSave()
              {
                  TrainingTechniques = await TrainingTechniqueConsumer.GetTechniques().ToListAsync();
                 await InvokeAsync(() =>
                  {
                      StateHasChanged();
                  });
              }
      
              protected void AddTrainingTechnique()
              {
                  TrainingTechniqueForm.Show();
              }
      
              protected async Task DeleteTechnique(int id)
              {
                 await TrainingTechniqueConsumer.DeleteTrainingTechnique(id);
                 TrainingTechniques =null;
                 TrainingTechniques = await TrainingTechniqueConsumer.GetTechniques().ToListAsync();
                 await InvokeAsync(() =>
                  {
                      StateHasChanged();
                  });
      
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-12-09
        • 1970-01-01
        • 2012-10-29
        • 2020-11-28
        • 1970-01-01
        • 1970-01-01
        • 2023-01-29
        相关资源
        最近更新 更多