在Blazor中添加具有typeparam作为属性的组件类

时间:2020-04-02 10:52:20

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

对于普通组件,只需将组件声明为私有属性,然后在组件定义中将名称添加为@type参数即可。

但是,当我添加带有typeparam的组件并按如下所示进行设置时,代码会编译并运行,但是该属性永远不会填充-它始终为null。请参阅最后一个代码块中的“ WantToDoAnUpdate”方法。我要在组件中强制进行更新,因为它使用分页并且不会通过常规的Blazor机制进行更新。

CardList.razor

@inherits ComponentComponentBase

@typeparam TItem

........................
create a table of values with pagination
..................

CardList.razor.cs

public partial class CardList<TItem> : ComponentComponentBase
{
  ......
  [Parameter]
  public IReadOnlyList<TItem> Items { get; set; }
  ......
  public void UpdateList()
  {
    ........
  }
}

DeliveryList.razor

@inherits PageComponentBase

<CardList@key="this._MyComponent" TItem="dbDelivery" ....>
</CardList>

DeliveryList.razor.cs

public partial class DeliveryList<TItem> : PageComponentBase
{
  ......
  private CardList<IReadOnlyList<dbDelivery>> _CardList { get; set; }
  ......

  public void WantToDoAnUpdate()
  {
  ....
    --ALWAYS NULL--
    if (this._CardList != null) this._CardList.UpdateList();
  }
}

我假设我错误地声明了 _CardList


太好了,谢谢您的答复。是的,我正在设置列表,只是没有在代码中包含该列表。 Cardlist使用提供的列表来生成分页列表(页面x的25个值),这就是问题所在。由于呈现的列表是分页过程从Items派生的新列表,因此,Items不会更新UI已更新。从父级调用UpdateList会对分页列表进行重新分页,并应该触发派生列表更新和UI更新。

但是,由于无法正常工作,我在Github上挖掘了Blazor的核心代码,以了解Blazor开发人员的工作方式。现在,我使用保存列表的逻辑层服务中的事件处理程序以不同的方式解决了该问题,而无需从父级向子级进行调用以进行更新。在其他实例(例如自定义输入/显示控件)中,我还使用了从属性上的设置触发的事件处理程序。

无论如何,再次感谢您抽出宝贵的时间来答复。

1 个答案:

答案 0 :(得分:0)

希望这能满足您的需求。我认为有两件事对您不利。

首先,在Cardlist子类中,您使用[Parameter]属性修饰了列表,但从未在调用代码中设置参数。您将需要同时设置TItemItems参数,以使其正常工作,因此Cardlist既知道列表包含什么类型,又知道在哪里找到列表。请记住,在C#中,列表是引用类型,因此,您设置的Items实际上只是对您提供的任何列表的引用,而不是以新形式或新列表的形式列出的。因此,您的DeliveryList应该具有如下所示的list属性:

public partial class DeliveryList : PageComponentBase
{
  ......
  private <IReadOnlyList<dbDelivery>> CardListContents { get; set; }
  ......
}  

然后在DeliveryList.razor中,将列表引用传递给Cardlist组件,如下所示:

<CardList @key="this._MyComponent" TItem="dbDelivery" Items="@CardListContents" ....>
</CardList>

现在,Cardlist组件成为通用类型外部列表的呈现工具。

第二,对于UpdateList应该执行的操作有一些歧义,但是我假设您正在连接一个按钮,当单击该按钮时,该列表将刷新。为此,您可以在Cardlist中使用事件回调。

您的Cardlist.razor现在变为:

@inherits ComponentComponentBase

@typeparam TItem

........................
create a table of values with pagination
..................
<button @onclick="OnUpdateButtonClickedCallBack">Update List</button>

您的Cardlist.razor.cs变为:

public partial class CardList<TItem> : ComponentComponentBase
{
  ......
  [Parameter]
  public IReadOnlyList<TItem> Items { get; set; }
  ......
  [Parameter]
  public EventCallBack OnUpdateButtonClickedCallBack { get; set;}
}

现在,您已设置为指向单击“更新列表”按钮时将执行的外部方法。

接下来,您需要在DeliveryList.razor.cs中连接一个方法,我们可以使用您的WantToUpdateList方法:

public partial class DeliveryList : PageComponentBase
{
  ......
  private <IReadOnlyList<dbDelivery>> CardListContents { get; set; }

  private WantToUpdateList()
  {
      //Since the list is read only you need to generate a new one
      //or call a method from elsewhere that returns a new one,
      //change the method below to suit your needs
      CardListContents = new IReadOnlylist<dbDelivery>();
  }
  ......
}  

现在,您可以在声明Cardlist时使用设置的EventCallback指向该方法。注意配置变得很长,所以我将其分为多行:

<CardList @key="this._MyComponent" 
          OnUpdateButtonClickedCallBack="@WantToUpdateList" //Sets the callback function
          TItem="dbDelivery" //Sets the type
          Items="@CardListContents" ....> //Points to the list
</CardList>

现在,您可以通过指定要使用的类型,列表和回调函数,将<Cardlist>组件与任何只读列表一起使用。 Cardlist成为一个独立的呈现工具,该列表的所有状态,逻辑和功能都位于调用组件内部的某个位置,从而使<CardList>真正通用且可移植。在此示例中,Blazor引擎应提取列表的所有更新并触发重新渲染,但如果没有,则可以在调用代码中将对StateHasChanged();的调用添加为Update方法的最后一行而且你应该做生意。

但是请注意,此解决方案尚未完成,因为您可能需要在RenderFragment中添加一些Cardlist逻辑来决定如何呈现表。

The .NET Core documentation does a great job of this here.看起来您可能已经看到了这一点,因为代码样式看起来很相似,并且这里为了清楚起见没有将其包括在内。

希望这会有所帮助!