ASP.NET-Blazor-从模板化组件返回单击的通用类型

时间:2020-05-20 18:29:44

标签: asp.net blazor

我正在学习Blazor和ASP.NET,并且过去6个月一直在学习C#。

我制作了一个简单的模板化组件:

@typeparam GenericType

<ul>
    @foreach (GenericType item in Items)
    { 
        <li @onclick="(x)=> ItemClicked(item)">FragmentToRender(item)</li>
    }    
</ul>

@code {
    [Parameter] public RenderFragment<GenericType> FragmentToRender { get; set; }

    [Parameter] public IReadOnlyList<GenericType> Items { get; set; }

    public void ItemClicked(GenericType item)
    {
         //To figure out...
    }
}

我正在页面组件中使用它:

<TestComponent GenericType="Thing" Items="ListOfThings">
    <FragmentToRender>
        <p>@context.Field</p>
    </FragmentToRender>
</TestComponent>

@code
{
    private List<Thing> ListOfThings =
        new List<Thing> {
            new Thing("Test"),
            new Thing("Test2")
        };

    public class Thing
    {
        public readonly string Field;

        public Thing(string field) => Field = field;
    }    
}

当触发组件中li元素的OnClick事件时,如何将项目的特定实例传递回页面组件(即,不同的组件可以对被单击的项目执行某些操作,例如将其数据上传到某处)?

非常感谢

2 个答案:

答案 0 :(得分:2)

您应该使用EventCallback传递数据。

@typeparam GenericType

<ul>
    @foreach (GenericType item in Items)
    { 
        <li @onclick="(x)=> ItemClicked(item)">FragmentToRender(item)</li>
    }    
</ul>

@code {
    [Parameter] public RenderFragment<GenericType> FragmentToRender { get; set; }

    [Parameter] public IReadOnlyList<GenericType> Items { get; set; }

    // Added EventCallback parameter
    [Parameter] public EventCallback<GenericType> OnClick { get; set; }

    public void ItemClicked(GenericType item)
    {
         // Checking if EventCallback is set
         if(OnClick.HasDelegate)
         {
             // Calling EventCallback
             OnClick.InvokeAsync(item);
         }
    }
}

然后将参数OnClick传递给该组件以获取商品

@* Passing the OnClick parameter *@
<TestComponent GenericType="Thing" Items="ListOfThings" OnClick="@HandleClick">
    <FragmentToRender>
        <p>@context.Field</p>
    </FragmentToRender>
</TestComponent>

@code
{

    private void HandleClick(Thing item)
    {
        // Do what you want with the item
    }

    private List<Thing> ListOfThings =
        new List<Thing> {
            new Thing("Test"),
            new Thing("Test2")
        };

    public class Thing
    {
        public readonly string Field;

        public Thing(string field) => Field = field;
    }    
}

答案 1 :(得分:1)

注意:我在您的代码示例中做了一些改动... 注意事项:

  • 在FragmentToRender(item)之前添加一个@符号。它指示编译器将FragmentToRender(item)视为可执行代码。否则,它将用作li元素的内容。

  • 在li元素的第二个版本中,我们将事件调用放回 lambda表达式的主体。如果您使用此版本,请注释
    ItemClicked方法。

TemplatedComponent.razor

 @typeparam GenericType

<ul>
    @foreach (GenericType item in Items)
    {
        <li @onclick="() => ItemClicked(item)">@FragmentToRender(item)</li>
        @*<li @onclick="@(() => SelectedItem.InvokeAsync(item))">@FragmentToRender(item)</li>*@
    }
</ul>

@code {
[Parameter] public RenderFragment<GenericType> FragmentToRender { get; set; }

[Parameter] public IReadOnlyList<GenericType> Items { get; set; }
// Define an event call back property.
[Parameter] public EventCallback<GenericType>  SelectedItem { get; set; }

public async Task ItemClicked(GenericType item)
{
    // Check if the event call back property contains a delegate. It's 
    // important to understand that the EventCallback type is not a true 
    // delegate. It is actually a struct that may contain a delegate 
    if(SelectedItem.HasDelegate)
    {
      await  SelectedItem.InvokeAsync(item);
    }

}
}

TestComponent.razor

<TemplatedComponent GenericType="Thing" Items="ListOfThings" 
                                     SelectedItem="SelectedItem">
    <FragmentToRender>
        <p>@context.Field</p>
    </FragmentToRender>
</TemplatedComponent>


@code
{
 // Define a method that will be called by the event call back 'delegate'. It
 // receives a single parameter from the calling delegate.
private async Task SelectedItem(Thing item)
{
    Console.WriteLine(item.Field);
    await Task.CompletedTask;
}
private List<Thing> ListOfThings =
    new List<Thing> {
        new Thing("Test"),
        new Thing("Test2")
        };

public class Thing
{
    public readonly string Field;

    public Thing(string field) => Field = field;
}
}

Index.razor

 @page "/"

<TestComponent/>

希望这对您有帮助...