【问题标题】:Blazor - Base Render in an inherited component doesn't use overridden methodsBlazor - 继承组件中的基本渲染不使用重写的方法
【发布时间】:2021-02-09 02:51:56
【问题描述】:

我正在尝试制作一个 Blazor 组件,然后我将专门化并覆盖一些方法。

基础组件“ZoomList”:

@inherits ComponentBase
<div>
    <table class="table">
        <thead>
            <tr>
                @foreach (var str in Headers())
                {
                    <th>@str</th>
                }
            </tr>
        </thead>
        <tbody>
            @foreach (var item in items)
            {
                <tr>
                    @foreach (var str in Rows(item))
                    {
                        <td>@str</td>
                    }
                </tr>
            }
        </tbody>
    </table>
</div>

@code {
    [Parameter]
    public List<Object> items { get; set; }

    protected virtual List<string> Rows(Object item) { return new List<string>() { "Placeholder" }; }
    protected virtual List<string> Headers() { return new List<string>() { "Placeholder" }; }
}

派生组件“ZoomCampaign”:

@inherits ZoomList
@using MyNamespace.Model

@{
    this.BuildRenderTree(__builder);
}

@code {

    protected override List<string> Rows(Object item)
    {
        Campaign camp = item as Campaign;
        return new List<string>() {
            camp.Id.ToString(),
            camp.Nom
        };
    }

    protected override List<string> Headers()
    {
        return new List<string>() { "#", "Name" };
    }
}

然后从另一个页面调用 ZoomCampaign。 但是 this.BuildRenderTree(__builder) 不使用被覆盖的方法,而是使用基本方法。 => 我的 html 数组包含“占位符”文本,而不是 ZoomCampaign 的覆盖方法“行”和“标题”中定义的文本。

我错过了什么?如何更改它,以便在渲染期间使用覆盖方法?

【问题讨论】:

    标签: inheritance razor blazor


    【解决方案1】:

    正如另一个答案中提到的,这不是组件的工作方式——特别是应该从 ZoomCampaign 中删除这段代码:

    @{
        this.BuildRenderTree(__builder);
    }
    

    您可以查看生成的代码 (ZoomCapaign.razor.g.cs) 看看出了什么问题。

    当您将该代码放在razor componentmarkup 中时,您基本上是在说“嘿,当您来渲染 ZoomCampaign 时,请渲染 ZoomCapaign”

    这比冗余(ZoomCapaign 已经被渲染)更糟糕,因为它引入了一个错误。

    解决方案

    删除上面提到的代码。 此外,您的 ZoomCapaign 组件不使用任何 Razor 功能,并且可以以更简单、更简洁(不太容易出现此类错误)的方式实现为 csharp 文件 ZoomCampaign.cs

    在这里试试:https://blazorrepl.com/repl/QvkQuMOX35G4Syyg08 _在此示例中我没有覆盖 Rows,因为我没有模型,但您可以看到 Headers 覆盖正在工作。

    【讨论】:

      【解决方案2】:

      我认为组件不应该以这种方式使用。不过,我找不到一个很好的解释为什么不支持您的方案。

      我会将问题分为两个不同的领域。首先,创建一个表格组件。

      表格组件

      <div>
          <table class="table">
              <thead>
                  <tr>
                      @foreach (var str in Headers)
                      {
                          <th>@str</th>
                      }
                  </tr>
              </thead>
              <tbody>
                  @foreach (var item in Items)
                  {
                      <tr>
                          @foreach (var str in Rows(item))
                          {
                              <td>@str</td>
                          }
                      </tr>
                  }
              </tbody>
          </table>
      </div>
      
      @code {
          [Parameter]
          public List<Object> Items { get; set; }
      
          [Parameter]
          public List<String> Headers { get; set; }
      
          [Parameter]
          public Func<Object, List<String>> RowGetter { get; set; }
      
          protected virtual List<string> Rows(Object item) => RowGetter?.Invoke(item);
      
      }
      
      

      我已将您的方法 Headers() 更改为属性 Headers 并引入了 Func&lt;Object,List&lt;String&gt;&gt; 作为属性,以根据行获取项目。两者都是参数,以便其他组件可以绑定它们。

      这个组件可以在你的ZoomList组件中使用

      <h3>ZoomList</h3>
      
      <Table Items="items" Headers="Headers()" RowGetter="Rows" />
      
      @code {
          [Parameter]
          public List<Object> items { get; set; }
      
          protected virtual List<string> Rows(Object item) { return new List<string>() { "Placeholder" }; }
          protected virtual List<string> Headers() { return new List<string>() { "Placeholder" }; }
      }
      
      

      在你的ZoomCampaign 中可能是这样的

      ZoomCampaign.razor

      @inherits ZoomList
      
      <Table Items="items" Headers="Headers()" RowGetter="Rows" />
      
      @code {
      
          protected override List<string> Rows(Object item)
          {
              Campaign camp = item as Campaign;
              return new List<string>() {
                  camp.Id.ToString(),
                  camp.Nom
              };
          }
      
          protected override List<string> Headers()
          {
              return new List<string>() { "#", "Name" };
          }
      }
      

      或者您可以创建没有自己的 UI 的组件。在这种情况下,您需要创建一个 .cs 而不是 .razor 文件。

      ZoomCampaign.cs

      public class ZoomCampaign : ZoomList
      {
          protected override List<string> Rows(Object item)
          {
              Campaign camp = item as Campaign;
              return new List<string>() {
              camp.Id.ToString(),
              camp.Nom
          };
          }
      
          protected override List<string> Headers()
          {
              return new List<string>() { "#", "Name" };
          }
      }
      

      另一种方法是在Table 组件上投入更多精力。您可以使其通用,并找到将“解析”逻辑传递到表中的方法,例如如何将 Campaign 拆分为列等。在这种情况下,您不需要继承功能。

      【讨论】:

        【解决方案3】:

        上面的答案是正确的,但可能没有说清楚发生了什么。

        您有一个名为 ZoomList 的 Razor 标记定义组件。构建完成后,您的标记将转换为 RenderTreeBuilder 代码(obj 构建文件夹中的 ZoomList.razor.g.cs)。

        然后定义继承自ZoomListZoomCampaign。但是,您通过调用 this.BuildRenderTree(__builder); 来重载继承的 Razor 代码,这会构建一个空组件 - 该方法没有主体。

        删除

        @{
            this.BuildRenderTree(__builder);
        }
        

        子组件渲染父组件的 Razor 标记。

        仅供参考,经典的 Hello World BuildRenderTree 如下所示:

        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
           builder.OpenElement(0, "div";
           builder.AddContent(1, "Hello World");
           builder.CloseElement();
        }
        

        把它放在ZoomCampaign的代码部分,看看你得到了什么。

        请注意,Microsoft 的文档建议您不要编写自己的 RenderTree 代码!

        【讨论】:

          猜你喜欢
          • 2020-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-21
          相关资源
          最近更新 更多