【问题标题】:How to render a component passed as an attribute如何渲染作为属性传递的组件
【发布时间】:2021-09-26 10:47:05
【问题描述】:

假设Row 是这样的组件:

<div class="row">
    <div class="col-6">
        @Column1
    </div>
    <div class="col-6">
        @Column2
    </div>
</div>

@code
{
    [Parameter]
    public ComponentBase Column1 { get; set; }

    [Parameter]
    public ComponentBase Column2 { get; set; }
}

然后假设我们像这样使用它:

<Row Column1="foo" Column2="foo"></Row>

@code {
    private readonly SomeComponent foo = new();
    private readonly SomeComponent bar = new();
}

我希望一行包含两列,其中包含 foobar 的渲染组件,但我得到两列包含“Example.Shared.Components.SomeComponent”

那么你如何渲染传递给其他组件的子组件?有没有更好的方法来做到这一点(即 Angular 中的 ng-content 之类的东西?

作为旁注,我正在寻找允许以编程方式(如上)并使用标记(如下)的解决方案:

<Row>
    <Column>
        <Foo></Foo>
    </Column>
    <Column>
        <Bar></Bar>
    </Column>
</Row>

【问题讨论】:

  • 你会如何使用它?在 Blazor 中,我们不传递组件的实例,RenderTreeBuilder 实例化它们。并不是说这完全不可能,但它看起来是错误的方式。
  • @HenkHolterman 抱歉,这是一个有点垃圾的例子。我已经更新了整个问题。

标签: c# blazor blazor-webassembly


【解决方案1】:

怎么样:

<div class="row">
    <div class="col-6">
        @Column1
    </div>
    <div class="col-6">
        @Column2
    </div>
</div>

@code
{
    [Parameter]
    public RenderFragment Column1 { get; set; }

    [Parameter]
    public RenderFragment Column2 { get; set; }
}

然后:

<Row>
  <Column1>
    <SomeComponent value="@somevalue"/>
  </Column1>
  <Column2>
   <SomeOtherComponent/>
  </Column2>
</Row>

如前所述,渲染器实例化所有组件并将它们附加到渲染树。

还要注意,所有组件不一定都继承自 ComponentBase,但它们都实现了 IComponent

【讨论】:

    【解决方案2】:

    Blazor 主要是声明性的。所以你应该:

    <Row>
        <Column1>
            <Foo></Foo>
        </Column1>
        <Column2>
            <Bar></Bar>
        </Column2>
    </Row> 
    

    你不需要new Foo() / new Bar()

    当然,您可以采用非常迂回的方式以编程方式填充RenderFragment。但这通常是不值得的。相反,请使用通用组件和多态性。

    【讨论】:

      【解决方案3】:

      我建议不要考虑用数据填充对象并传递对象。我认为组件是现有数据在 html 空间中的表达。请注意,对于每一层数据,我都嵌套了 Razor 组件。因此,您将 DATA 传递给 Table 组件,而不是 RenderFragments 或任何其他类型的对象。为了清楚起见,以下内容进行了简化。

      class TableData {
          public List<RowData> Rows;
      }
      class RowData {
          public List<ColumnData> Columns;
      }
      class ColumnData {
          public string DisplayString;
      }
      

      TableComponent.razor

      @foreach (var row in TableData.Rows){
          <DataRowComponent Data=row />
      }
      @code {
          [Parameter]
          public TableData TableData{get; set;}
      }
      

      DataRowComponent.razor

      @foreach (var column in Data.Columns ){
          <DataColumnComponent Data=column />
      }
      @code {
          [Parameter]
          public RowData Data {get; set;}
      }
      

      DataColumnComponent.razor

      <div>
          @Data.DisplayString
      </div>
      
      @code {
          [Parameter]
          public ColumnData Data {get; set;}
      }
      

      【讨论】:

        【解决方案4】:

        你想要的是templated components

        你仍然不能使用SomeComponent foo = new();

        实例化留给渲染器。但是考虑到这是一件好事,它可以让您在(项目)上下文中滑倒。

        您还需要查看Cascading values,以将行暴露给列。

        最后,Blazor DataGrid 有很多商业版本和Open 版本。不要重新发明整个轮子。

        【讨论】:

        • 你的最后一段最好是评论,而不是答案的一部分……他没有征求你的意见。他想要一个编程问题的解决方案。
        • 我有时同意 enet。这是其中之一——我不会用关于 3rd 方控件的建议来回答编程问题。
        • @Bennyboy1973 “打开”。 DataGrid 的一个很好的例子值得很多 SO 答案。
        • 我 +1 你的帖子和你对我的评论。但就个人而言,我认为他会更好地重新发明轮子。
        猜你喜欢
        • 2021-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-11
        • 2022-01-06
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        相关资源
        最近更新 更多