Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Viktigt!
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Av Robert Haken
Den här artikeln förklarar hur mallkomponenter kan acceptera en eller flera användargränssnittsmallar som parametrar, som sedan kan användas som en del av komponentens renderingslogik.
Mallbaserade komponenter
Mallkomponenter är komponenter som tar emot en eller flera användargränssnittsmallar som parametrar, som kan användas i komponentens renderingslogik. Med hjälp av mallkomponenter kan du skapa komponenter på högre nivå som är mer återanvändbara. Exempel är:
- En tabellkomponent som gör att en användare kan ange mallar för tabellens sidhuvud, rader och sidfot.
- En listkomponent som gör att en användare kan ange en mall för återgivning av objekt i en lista.
- En komponent i navigeringsfältet som gör att en användare kan ange en mall för startinnehåll och navigeringslänkar.
En mallkomponent definieras genom att ange en eller flera komponentparametrar av typen RenderFragment eller RenderFragment<TValue>. Ett återgivningsfragment representerar ett segment av användargränssnittet som ska återges. RenderFragment<TValue> tar en typparameter som kan anges när återgivningsfragmentet anropas.
Anmärkning
Mer information om RenderFragmentfinns i ASP.NET Core Razor-komponenter.
Ofta skrivs mallade komponenter allmänt, som följande TemplatedNavBar komponent (TemplatedNavBar.razor) visar. Den generiska typen (<T>) i följande exempel används för att återge IReadOnlyList<T> värden, vilket i det här fallet är en lista över husdjur för en komponent som visar ett navigeringsfält med länkar till en komponent för husdjursinformation.
              TemplatedNavBar.razor:
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
    <div class="container justify-content-start">
        @StartContent
        <div class="navbar-nav">
            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }
        </div>
    </div>
</nav>
@code {
    [Parameter]
    public RenderFragment? StartContent { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
    <div class="container justify-content-start">
        @StartContent
        <div class="navbar-nav">
            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }
        </div>
    </div>
</nav>
@code {
    [Parameter]
    public RenderFragment? StartContent { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
    <div class="container justify-content-start">
        @StartContent
        <div class="navbar-nav">
            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }
        </div>
    </div>
</nav>
@code {
    [Parameter]
    public RenderFragment? StartContent { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
    <div class="container justify-content-start">
        @StartContent
        <div class="navbar-nav">
            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }
        </div>
    </div>
</nav>
@code {
    [Parameter]
    public RenderFragment? StartContent { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
    <div class="container justify-content-start">
        @StartContent
        <div class="navbar-nav">
            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }
        </div>
    </div>
</nav>
@code {
    [Parameter]
    public RenderFragment StartContent { get; set; }
    [Parameter]
    public RenderFragment<TItem> ItemTemplate { get; set; } = default;
    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; } = default;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
    <div class="container justify-content-start">
        @StartContent
        <div class="navbar-nav">
            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }
        </div>
    </div>
</nav>
@code {
    [Parameter]
    public RenderFragment StartContent { get; set; }
    [Parameter]
    public RenderFragment<TItem> ItemTemplate { get; set; } = default;
    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; } = default;
}
När du använder en mallkomponent kan du ange mallparametrarna med underordnade element som matchar parametrarnas namn. I följande exempel anges <StartContent>...</StartContent> och <ItemTemplate>...</ItemTemplate> som mallar för RenderFragment<TValue> för StartContent och ItemTemplate i komponenten TemplatedNavBar.
              Context Ange attributet för komponentelementet när du vill ange namnet på innehållsparametern för implicit underordnat innehåll (utan omslutande underordnat element). I följande exempel Context visas attributet på elementet TemplatedNavBar och gäller för alla RenderFragment<TValue> mallparametrar.
              Pets1.razor:
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-1")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-1")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-1")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-1"
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
@page "/pets-1"
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
Du kan också ändra parameternamnet med hjälp av Context attributet för det RenderFragment<TValue> underordnade elementet. I följande exempel är Context inställd på ItemTemplate istället för TemplatedNavBar.
              Pets2.razor:
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate Context="pet">
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-2")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate Context="pet">
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-2")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate Context="pet">
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-2")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate Context="pet">
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-2"
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate Context="pet">
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
@page "/pets-2"
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate Context="pet">
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
Komponentargument av typen RenderFragment<TValue> har en implicit parameter med namnet context, som kan användas. I följande exempel Context anges inte. 
              @context.{PROPERTY} tillhandahåller värden för husdjur till mallen, där {PROPERTY} är en Pet egenskap:
              Pets3.razor:
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{context.PetId}?ReturnUrl=%2Fpets-3")" class="nav-link">
            @context.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{context.PetId}?ReturnUrl=%2Fpets-3")" class="nav-link">
            @context.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{context.PetId}?ReturnUrl=%2Fpets-3")" class="nav-link">
            @context.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{context.PetId}")" class="nav-link">
            @context.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-3"
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{context.PetId}")" class="nav-link">
            @context.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
@page "/pets-3"
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{context.PetId}")" class="nav-link">
            @context.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
När du använder generiska typer härleds typparametern om möjligt. Du kan dock uttryckligen ange typen med ett attribut som har ett namn som matchar typparametern, som finns TItem i föregående exempel:
              Pets4.razor:
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-4")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 4, Name = "Salem Saberhagen" },
        new Pet { PetId = 7, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-4")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 4, Name = "Salem Saberhagen" },
        new Pet { PetId = 7, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-4")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 4, Name = "Salem Saberhagen" },
        new Pet { PetId = 7, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 4, Name = "Salem Saberhagen" },
        new Pet { PetId = 7, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-4"
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 4, Name = "Salem Saberhagen" },
        new Pet { PetId = 7, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
@page "/pets-4"
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
    <StartContent>
        <a href="/" class="navbar-brand">PetsApp</a>
    </StartContent>
    <ItemTemplate>
        <NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
            @pet.Name
        </NavLink>
    </ItemTemplate>
</TemplatedNavBar>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 4, Name = "Salem Saberhagen" },
        new Pet { PetId = 7, Name = "K-9" }
    };
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
Exemplet i komponenten TemplatedNavBar (TemplatedNavBar.razor) förutsätter att Items samlingen inte ändras efter den första återgivningen, eller att om den ändras är det inte nödvändigt att behålla tillståndet för komponenter/element som används i ItemTemplate . Information om mallkomponenter där sådan användning inte kan förväntas finns i avsnittet Bevara relationer med @key .
Bevara relationer med @key
Mallkomponenter används ofta för att återge samlingar av objekt, till exempel tabeller eller listor. I sådana allmänna scenarier kan vi inte förutsätta att användaren undviker tillståndskänsliga komponenter/element i objektmalldefinitionen eller att det inte blir ytterligare ändringar i Items samlingen. För sådana mallkomponenter är det nödvändigt att bevara relationerna med direktivattributet @key .
Anmärkning
Mer information om direktivattributet @key finns i Behåll element-, komponent- och modellrelationer i ASP.NET Core Blazor.
Följande TableTemplate komponent (TableTemplate.razor) visar en mallkomponent som bevarar relationer med @key.
              TableTemplate.razor:
@typeparam TItem
<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr @key="@item">@RowTemplate(item)</tr>
        }
    </tbody>
</table>
@code {
    [Parameter]
    public RenderFragment? TableHeader { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> RowTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr @key="@item">@RowTemplate(item)</tr>
        }
    </tbody>
</table>
@code {
    [Parameter]
    public RenderFragment? TableHeader { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> RowTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr @key="@item">@RowTemplate(item)</tr>
        }
    </tbody>
</table>
@code {
    [Parameter]
    public RenderFragment? TableHeader { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> RowTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr @key="@item">@RowTemplate(item)</tr>
        }
    </tbody>
</table>
@code {
    [Parameter]
    public RenderFragment? TableHeader { get; set; }
    [Parameter, EditorRequired]
    public RenderFragment<TItem> RowTemplate { get; set; } = default!;
    [Parameter, EditorRequired]
    public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr @key="@item">@RowTemplate(item)</tr>
        }
    </tbody>
</table>
@code {
    [Parameter]
    public RenderFragment TableHeader { get; set; }
    [Parameter]
    public RenderFragment<TItem> RowTemplate { get; set; } = default;
    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; } = default;
}
@typeparam TItem
<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr @key="@item">@RowTemplate(item)</tr>
        }
    </tbody>
</table>
@code {
    [Parameter]
    public RenderFragment TableHeader { get; set; }
    [Parameter]
    public RenderFragment<TItem> RowTemplate { get; set; } = default;
    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; } = default;
}
Tänk på följande Pets5 komponent (Pets5.razor), som visar vikten av att nyckeldata bevarar modellrelationer. I komponenten leder varje iteration av att lägga till ett husdjur i OnAfterRenderAsync till att Blazor renderar om TableTemplate-komponenten.
              Pets5.razor:
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td><input value="@pet.PetId" /></td>
        <td><input value="@pet.Name" /></td>
    </RowTemplate>
</TableTemplate>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Insert new pet every 5 seconds
        if (pets.Count < 10)
        {
            await Task.Delay(5000);
            pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
            StateHasChanged();
        }
    }
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td><input value="@pet.PetId" /></td>
        <td><input value="@pet.Name" /></td>
    </RowTemplate>
</TableTemplate>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Insert new pet every 5 seconds
        if (pets.Count < 10)
        {
            await Task.Delay(5000);
            pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
            StateHasChanged();
        }
    }
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td><input value="@pet.PetId" /></td>
        <td><input value="@pet.Name" /></td>
    </RowTemplate>
</TableTemplate>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Insert new pet every 5 seconds
        if (pets.Count < 10)
        {
            await Task.Delay(5000);
            pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
            StateHasChanged();
        }
    }
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td><input value="@pet.PetId" /></td>
        <td><input value="@pet.Name" /></td>
    </RowTemplate>
</TableTemplate>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Insert new pet every 5 seconds
        if (pets.Count < 10)
        {
            await Task.Delay(5000);
            pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
            StateHasChanged();
        }
    }
    private class Pet
    {
        public int PetId { get; set; }
        public string? Name { get; set; }
    }
}
@page "/pets-5"
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td><input value="@pet.PetId" /></td>
        <td><input value="@pet.Name" /></td>
    </RowTemplate>
</TableTemplate>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Insert new pet every 5 seconds
        if (pets.Count < 10)
        {
            await Task.Delay(5000);
            pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
            StateHasChanged();
        }
    }
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
@page "/pets-5"
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td><input value="@pet.PetId" /></td>
        <td><input value="@pet.Name" /></td>
    </RowTemplate>
</TableTemplate>
@code {
    private List<Pet> pets = new()
    {
        new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
        new Pet { PetId = 2, Name = "Salem Saberhagen" },
        new Pet { PetId = 3, Name = "K-9" }
    };
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Insert new pet every 5 seconds
        if (pets.Count < 10)
        {
            await Task.Delay(5000);
            pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
            StateHasChanged();
        }
    }
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
    }
}
Med den här demonstrationen kan du:
- Välj en <input>bland flera renderade tabellrader.
- Studera beteendet för sidans fokus när husdjurssamlingen växer automatiskt.
Utan att använda direktivattributet @key i komponenten TableTemplate förblir fokuset på samma radposition i tabellen, vilket gör att fokuset flyttas varje gång ett husdjur läggs till. För att demonstrera detta tar du bort direktivattributet @key och -värdet, startar om appen och försöker ändra ett fältvärde när objekt läggs till.
Ytterligare resurser
ASP.NET Core