Criar componentes de interface do usuário reutilizáveis com o Blazor
Dica
Esse conteúdo é um trecho do livro eletrônico, Blazor para Desenvolvedores do ASP NET Web Forms para o Azure, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.
Uma das melhores coisas sobre o ASP.NET Web Forms é como ele permite o encapsulamento de partes reutilizáveis do código de interface do usuário em controles da interface do usuário reutilizáveis. Os controles de usuário personalizados podem ser definidos na marcação por meio de arquivos .ascx. Você também pode criar controles de servidor elaborados em código com suporte completo ao designer.
O Blazor também dá suporte ao encapsulamento de interface do usuário por meio de componentes. Um componente:
- É uma parte autossuficiente da interface do usuário.
- Mantém seu próprio estado e lógica de renderização.
- Pode definir manipuladores de eventos de interface do usuário, vincular-se a dados de entrada e gerenciar seu próprio ciclo de vida.
- Normalmente, é definido em um arquivo .razor usando sintaxe Razor.
Uma introdução ao Razor
O Razor é uma linguagem de marcação leve baseada em HTML e C#. Com o Razor, você pode fazer a transição direta entre a marcação e o código C# para definir a lógica de renderização do componente. Quando o arquivo .razor é compilado, a lógica de renderização é capturada de maneira estruturada em uma classe .NET. O nome da classe compilada é retirado do nome do arquivo .razor. O namespace é retirado do namespace padrão do projeto e do caminho da pasta, ou você pode especificar explicitamente o namespace usando a diretiva @namespace
(mais sobre as diretivas Razor abaixo).
A lógica de renderização de um componente é criada por meio de marcação HTML normal com lógica dinâmica adicionada por meio de C#. O caractere @
é usado para fazer a transição para C#. O Razor normalmente é inteligente em relação a descobrir quando você alternou novamente para HTML. Por exemplo, o componente abaixo renderiza uma marca <p>
com a hora atual:
<p>@DateTime.Now</p>
Para especificar explicitamente o início e o término de uma expressão C#, use parênteses:
<p>@(DateTime.Now)</p>
O Razor também facilita o uso do fluxo de controle do C# em sua lógica de renderização. Por exemplo, você pode renderizar condicionalmente algum HTML como este:
@if (value % 2 == 0)
{
<p>The value was even.</p>
}
Ou pode gerar uma lista de itens usando um loop C# foreach
normal como este:
<ul>
@foreach (var item in items)
{
<li>@item.Text</li>
}
</ul>
As diretivas Razor, como as diretivas ASP.NET Web Forms, controlam muitos aspectos de como um componente Razor é compilado. Os exemplos incluem os seguintes aspectos do componente:
- Namespace
- Classe base
- Interfaces implementadas
- Parâmetros genéricos
- Namespaces importados
- Rotas
As diretivas Razor começam com o caractere @
e normalmente são usadas no início de uma nova linha no início do arquivo. Por exemplo, a diretiva @namespace
define o namespace do componente:
@namespace MyComponentNamespace
A tabela abaixo resume as várias diretivas Razor usadas no Blazor e seus ASP.NET Web Forms equivalentes, se existirem.
Diretiva | Descrição | Exemplo | Equivalente do Web Forms |
---|---|---|---|
@attribute |
Adiciona um atributo de nível de classe ao componente | @attribute [Authorize] |
Nenhum |
@code |
Adiciona membros de classe ao componente | @code { ... } |
<script runat="server">...</script> |
@implements |
Implementa a interface especificada | @implements IDisposable |
Usar code-behind |
@inherits |
Herda da classe base especificada | @inherits MyComponentBase |
<%@ Control Inherits="MyUserControlBase" %> |
@inject |
Injeta um serviço no componente | @inject IJSRuntime JS |
Nenhum |
@layout |
Especifica um componente de layout para o componente | @layout MainLayout |
<%@ Page MasterPageFile="~/Site.Master" %> |
@namespace |
Define o namespace para o componente | @namespace MyNamespace |
Nenhum |
@page |
Especifica a rota para o componente | @page "/product/{id}" |
<%@ Page %> |
@typeparam |
Especifica um parâmetro de tipo genérico para o componente | @typeparam TItem |
Usar code-behind |
@using |
Especifica um namespace para colocar no escopo | @using MyComponentNamespace |
Adicionar namespace ao web.config |
Os componentes Razor também fazem uso extensivo de atributos de diretiva em elementos para controlar vários aspectos de como os componentes são compilados (manipulação de eventos, associação de dados, referências de elemento e de componente e assim por diante). Todos os atributos de diretiva seguem uma sintaxe genérica comum em que os valores entre parênteses são opcionais:
@directive(-suffix(:name))(="value")
A tabela a seguir resume os vários atributos para diretivas Razor usados no Blazor.
Atributo | Descrição | Exemplo |
---|---|---|
@attributes |
Renderiza um dicionário de atributos | <input @attributes="ExtraAttributes" /> |
@bind |
Cria uma associação de dados de duas vias | <input @bind="username" @bind:event="oninput" /> |
@on{event} |
Adiciona um manipulador de eventos para o evento especificado | <button @onclick="IncrementCount">Click me!</button> |
@key |
Especifica uma chave a ser usada pelo algoritmo de diferenciação para preservar elementos em uma coleção | <DetailsEditor @key="person" Details="person.Details" /> |
@ref |
Captura uma referência ao componente ou elemento HTML | <MyDialog @ref="myDialog" /> |
Os vários atributos de diretiva usados por Blazor (@onclick
, @bind
, @ref
e assim por diante) são abordados nas seções abaixo e nos capítulos posteriores.
Muitas das sintaxes usadas em arquivos .aspx e .ascx têm sintaxes paralelas no Razor. Abaixo está uma comparação simples das sintaxes para ASP.NET Web Forms e Razor.
Recurso | Web Forms | Sintaxe | Razor | Sintaxe |
---|---|---|---|---|
Diretivas | <%@ [directive] %> |
<%@ Page %> |
@[directive] |
@page |
Blocos de códigos | <% %> |
<% int x = 123; %> |
@{ } |
@{ int x = 123; } |
Expressões (Codificado em HTML) |
<%: %> |
<%:DateTime.Now %> |
Implícito: @ Explícito: @() |
@DateTime.Now @(DateTime.Now) |
Comentários | <%-- --%> |
<%-- Commented --%> |
@* *@ |
@* Commented *@ |
Vinculação de dados | <%# %> |
<%# Bind("Name") %> |
@bind |
<input @bind="username" /> |
Para adicionar membros à classe de componente Razor, use a diretiva @code
. Essa técnica é semelhante ao uso de um bloco <script runat="server">...</script>
em um controle de usuário ou página do ASP.NET Web Forms.
@code {
int count = 0;
void IncrementCount()
{
count++;
}
}
Como o Razor é baseado em C#, ele precisa ser compilado de dentro de um projeto em C# (.csproj). Não é possível compilar arquivos .razor de um projeto Visual Basic (.vbproj). Você ainda pode fazer referência a projetos do Visual Basic do seu projeto do Blazor. O oposto também é verdadeiro.
Para obter uma referência de sintaxe Razor completa, confira Referência de sintaxe Razor para ASP.NET Core.
Usar componentes
Além do HTML normal, os componentes também podem usar outros componentes como parte de sua lógica de renderização. A sintaxe para usar um componente no Razor é semelhante ao uso de um controle de usuário em um aplicativo ASP.NET Web Forms. Os componentes são especificados com uma marca de elemento que corresponde ao nome do tipo do componente. Por exemplo, você pode adicionar um componente Counter
como este:
<Counter />
Diferentemente do ASP.NET Web Forms, os componentes no Blazor:
- Não usam um prefixo de elemento (por exemplo,
asp:
). - Não exigem o registro na página ou no web.config.
Pense nos componentes do Razor como se fossem tipos do .NET, pois é exatamente o que eles são. Se o assembly que contém o componente for referenciado, o componente estará disponível para uso. Para colocar o namespace do componente no escopo, aplique a diretiva @using
:
@using MyComponentLib
<Counter />
Como visto nos projetos do Blazor, é comum colocar diretivas @using
em um arquivo _Imports.razor para que elas sejam importadas para todos os arquivos .razor no mesmo diretório e em diretórios filho.
Se o namespace de um componente não estiver no escopo, você poderá especificar um componente usando seu nome de tipo completo, como faz em C#:
<MyComponentLib.Counter />
Modificar o título da página dos componentes
Ao criar aplicativos no estilo SPA, é comum que partes de uma página sejam recarregadas sem ser a página inteira. Mesmo assim, pode ser útil ver o título da página mudar com base em qual componente está carregado no momento. Isso pode ser feito incluindo a marca <PageTitle>
na página Razor do componente:
@page "/"
<PageTitle>Home</PageTitle>
O conteúdo desse elemento pode ser dinâmico, por exemplo, mostrar a contagem atual de mensagens:
<PageTitle>@MessageCount messages</PageTitle>
Observe que se vários componentes em uma página específica incluírem macas <PageTitle>
, somente o último será exibido (pois cada um substituirá o anterior).
Parâmetros do componente
No ASP.NET Web Forms, você pode fluir parâmetros e dados para controles por meio de propriedades públicas. Essas propriedades podem ser definidas na marcação com atributos ou definidas diretamente no código. Os componentes do Razor funcionam de maneira semelhante, embora as propriedades do componente também precisem ser marcadas com o atributo [Parameter]
para serem consideradas parâmetros de componente.
O componente Counter
a seguir define um parâmetro de componente chamado IncrementAmount
que pode ser usado para especificar a quantidade de incremento de Counter
sempre que o botão é clicado.
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
int currentCount = 0;
[Parameter]
public int IncrementAmount { get; set; } = 1;
void IncrementCount()
{
currentCount+=IncrementAmount;
}
}
Para especificar um parâmetro de componente no Blazor, use um atributo como faria no ASP.NET Web Forms:
<Counter IncrementAmount="10" />
Parâmetros de cadeia de caracteres de consulta
Os componentes do Razor também podem aproveitar valores da cadeia de caracteres de consulta da página em que são renderizados como uma fonte de parâmetro. Para habilitar isso, adicione o atributo [SupplyParameterFromQuery]
ao parâmetro. Por exemplo, a definição de parâmetro a seguir obteria seu valor da solicitação no formato ?IncBy=2
:
[Parameter]
[SupplyParameterFromQuery(Name = "IncBy")]
public int IncrementAmount { get; set; } = 1;
Se você não fornecer um Name
personalizado no atributo [SupplyParameterFromQuery]
, por padrão, ele corresponderá ao nome da propriedade (IncrementAmount
nesse caso).
Componentes e limites de erro
Por padrão, os aplicativos Blazor detectarão exceções sem tratamento e mostrarão uma mensagem de erro na parte inferior da página sem detalhes adicionais. Para restringir as partes do aplicativo que são afetadas por um erro sem tratamento, por exemplo, para limitar o impacto a um único componente, a marca <ErrorBoundary>
pode ser encapsulada em declarações de componente.
Por exemplo, para proteger contra possíveis exceções lançadas pelo componente Counter
, declare-a dentro de um <ErrorBoundary>
e, opcionalmente, especifique uma mensagem a ser exibida se houver uma exceção:
<ErrorBoundary>
<ChildContent>
<Counter />
</ChildContent>
<ErrorContent>
Oops! The counter isn't working right now; please try again later.
</ErrorContent>
</ErrorBoundary>
Se você não precisar especificar o conteúdo de erro personalizado, basta encapsular o componente diretamente:
<ErrorBoundary>
<Counter />
</ErrorBoundary>
Uma mensagem padrão informando "Um erro ocorreu" será exibida se ocorrer uma exceção sem tratamento no componente encapsulado.
Manipuladores de eventos
Tanto o ASP.NET Web Forms quanto o Blazor fornecem um modelo de programação baseado em evento para manipular eventos de interface do usuário. Exemplos desses eventos incluem cliques de botão e entrada de texto. No ASP.NET Web Forms, você usa controles de servidor HTML para manipular eventos de interface do usuário expostos pelo DOM ou pode manipular eventos expostos por controles de servidor Web. Os eventos são revelados no servidor por meio de solicitações de post-back de formulário. Considere o seguinte exemplo de clique no botão do Web Forms:
Counter.ascx
<asp:Button ID="ClickMeButton" runat="server" Text="Click me!" OnClick="ClickMeButton_Click" />
Counter.ascx.cs
public partial class Counter : System.Web.UI.UserControl
{
protected void ClickMeButton_Click(object sender, EventArgs e)
{
Console.WriteLine("The button was clicked!");
}
}
No Blazor, você pode registrar manipuladores para eventos de interface do usuário DOM diretamente usando atributos de diretiva do formulário @on{event}
. O espaço reservado {event}
representa o nome do evento. Por exemplo, você pode escutar cliques de botão como este:
<button @onclick="OnClick">Click me!</button>
@code {
void OnClick()
{
Console.WriteLine("The button was clicked!");
}
}
Os manipuladores de eventos podem aceitar um argumento opcional específico do evento para fornecer mais informações sobre o evento. Por exemplo, eventos de mouse podem usar um argumento MouseEventArgs
, mas não é obrigatório.
<button @onclick="OnClick">Click me!</button>
@code {
void OnClick(MouseEventArgs e)
{
Console.WriteLine($"Mouse clicked at {e.ScreenX}, {e.ScreenY}.");
}
}
Em vez de se referir a um grupo de métodos para um manipulador de eventos, você pode usar uma expressão lambda. Uma expressão lambda permite que você envolva outros valores no escopo.
@foreach (var buttonLabel in buttonLabels)
{
<button @onclick="() => Console.WriteLine($"The {buttonLabel} button was clicked!")">@buttonLabel</button>
}
Manipuladores de eventos podem ser executados de forma síncrona ou assíncrona. Por exemplo, o manipulador de eventos OnClick
abaixo é executado de forma assíncrona:
<button @onclick="OnClick">Click me!</button>
@code {
async Task OnClick()
{
var result = await Http.GetAsync("api/values");
}
}
Depois que um evento é tratado, o componente é renderizado para levar em conta todas as alterações de estado do componente. Com manipuladores de eventos assíncronos, o componente é renderizado imediatamente após a conclusão da execução do manipulador. O componente é renderizado novamente após a conclusão assíncronaTask
. Esse modo de execução assíncrona fornece uma oportunidade de renderizar alguma interface do usuário apropriada enquanto a Task
assíncrona ainda está em andamento.
<button @onclick="ShowMessage">Get message</button>
@if (showMessage)
{
@if (message == null)
{
<p><em>Loading...</em></p>
}
else
{
<p>The message is: @message</p>
}
}
@code
{
bool showMessage = false;
string message;
public async Task ShowMessage()
{
showMessage = true;
message = await MessageService.GetMessageAsync();
}
}
Os componentes também podem definir seus próprios eventos com a definição de um parâmetro de componente do tipo EventCallback<TValue>
. Os retornos de chamada de evento dão suporte a todas as variações de manipuladores de eventos da interface do usuário DOM: argumentos opcionais, síncronos ou assíncronos, grupos de métodos ou expressões lambda.
<button class="btn btn-primary" @onclick="OnClick">Click me!</button>
@code {
[Parameter]
public EventCallback<MouseEventArgs> OnClick { get; set; }
}
Vinculação de dados
O Blazor fornece um mecanismo simples para vincular dados de um componente de interface do usuário ao estado do componente. Essa abordagem difere dos recursos no ASP.NET Web Forms para vincular dados de fontes de dados a controles de interface do usuário. Vamos abordar o tratamento de dados de diferentes fontes de dados na seção Lidando com dados.
Para criar uma associação de dados de duas vias de um componente de interface do usuário para o estado do componente, use o atributo de diretiva @bind
. No exemplo a seguir, o valor da caixa de seleção é vinculado ao campo isChecked
.
<input type="checkbox" @bind="isChecked" />
@code {
bool isChecked;
}
Quando o componente é renderizado, o valor da caixa de seleção é definido como o valor do campo isChecked
. Quando o usuário alterna a caixa de seleção, o evento onchange
é acionado e o campo isChecked
é definido como o novo valor. Nesse caso, a sintaxe de @bind
é equivalente à seguinte marcação:
<input value="@isChecked" @onchange="(UIChangeEventArgs e) => isChecked = e.Value" />
Para alterar o evento usado na vinculação, use o atributo @bind:event
.
<input @bind="text" @bind:event="oninput" />
<p>@text</p>
@code {
string text;
}
Os componentes também podem dar suporte à associação de dados para seus parâmetros. Para vincular dados, defina um parâmetro de retorno de chamada de evento com o mesmo nome do parâmetro associável. O sufixo "Changed" é adicionado ao nome.
PasswordBox.razor
Password: <input
value="@Password"
@oninput="OnPasswordChanged"
type="@(showPassword ? "text" : "password")" />
<label><input type="checkbox" @bind="showPassword" />Show password</label>
@code {
private bool showPassword;
[Parameter]
public string Password { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
private Task OnPasswordChanged(ChangeEventArgs e)
{
Password = e.Value.ToString();
return PasswordChanged.InvokeAsync(Password);
}
}
Para encadear uma associação de dados a um elemento de interface do usuário subjacente, defina o valor e manipular o evento diretamente no elemento de interface do usuário em vez de usar o atributo@bind
.
Para associar um parâmetro de componente, use um atributo @bind-{Parameter}
para especificar o parâmetro ao qual você deseja associar.
<PasswordBox @bind-Password="password" />
@code {
string password;
}
Alterações de estado
Se o estado do componente tiver sido alterado fora de um evento de interface do usuário normal ou retorno de chamada de evento, o componente precisará sinalizar manualmente que precisa ser renderizado novamente. Para sinalizar que o estado de um componente foi alterado, chame o método StateHasChanged
no componente.
No exemplo a seguir, um componente exibe uma mensagem de um serviço AppState
que pode ser atualizado por outras partes do aplicativo. O componente registra seu método StateHasChanged
com o evento AppState.OnChange
para que o componente seja renderizado sempre que a mensagem for atualizada.
public class AppState
{
public string Message { get; }
// Lets components receive change notifications
public event Action OnChange;
public void UpdateMessage(string message)
{
Message = message;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
@inject AppState AppState
<p>App message: @AppState.Message</p>
@code {
protected override void OnInitialized()
{
AppState.OnChange += StateHasChanged
}
}
Ciclo de vida do componente
A estrutura ASP.NET Web Forms tem métodos de ciclo de vida bem definidos para módulos, páginas e controles. Por exemplo, o controle a seguir implementa manipuladores de eventos para os eventos de ciclo de vida Init
, Load
e UnLoad
:
Counter.ascx.cs
public partial class Counter : System.Web.UI.UserControl
{
protected void Page_Init(object sender, EventArgs e) { ... }
protected void Page_Load(object sender, EventArgs e) { ... }
protected void Page_UnLoad(object sender, EventArgs e) { ... }
}
Os componentes do Razor também têm um ciclo de vida bem definido. O ciclo de vida de um componente pode ser usado para inicializar o estado do componente e implementar comportamentos avançados de componentes.
Todos os métodos de ciclo de vida de componente do Blazor têm versões síncronas e assíncronas. A renderização de componentes é síncrona. Não é possível executar a lógica assíncrona como parte da renderização do componente. Toda lógica assíncrona precisa ser executada como parte de um método de ciclo de vida async
.
OnInitialized
Os métodos OnInitialized
e OnInitializedAsync
são usados para inicializar o componente. Um componente normalmente é inicializado após ser renderizado pela primeira vez. Depois que um componente é inicializado, ele pode ser renderizado várias vezes antes de ser eventualmente descartado. O método OnInitialized
é semelhante ao evento Page_Load
em páginas e controles do ASP.NET Web Forms.
protected override void OnInitialized() { ... }
protected override async Task OnInitializedAsync() { await ... }
OnParametersSet
Os métodos OnParametersSet
e OnParametersSetAsync
são chamados quando um componente recebe parâmetros de seu pai e o valor é atribuído às propriedades. Esses métodos são executados após a inicialização do componente e cada vez que o componente é renderizado.
protected override void OnParametersSet() { ... }
protected override async Task OnParametersSetAsync() { await ... }
OnAfterRender
Os métodos OnAfterRender
e OnAfterRenderAsync
são chamados depois que um componente termina a renderização. As referências de elemento e componente são preenchidas nesse ponto (mais sobre esses conceitos abaixo). A interatividade com o navegador está habilitada aqui. As interações com a execução de DOM e JavaScript podem ocorrer com segurança.
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
...
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await ...
}
}
OnAfterRender
e OnAfterRenderAsync
não são chamados quando estão em pré-renderização no servidor.
O parâmetro firstRender
é true
na primeira vez em que o componente é renderizado; do contrário, o valor é false
.
IDisposable
Os componentes do Razor podem implementar IDisposable
para descartar recursos quando o componente é removido da interface do usuário. Um componente do Razor pode implementar IDispose
usando a diretiva @implements
:
@using System
@implements IDisposable
...
@code {
public void Dispose()
{
...
}
}
Capturar referências de componente
No ASP.NET Web Forms, é comum manipular uma instância de controle diretamente no código com referência à sua ID. No Blazor, também é possível capturar e manipular uma referência a um componente, embora seja muito menos comum.
Para capturar uma referência de componente no Blazor, use o atributo de diretiva @ref
. O valor do atributo deve corresponder ao nome de um campo configurável com o mesmo tipo do componente referenciado.
<MyLoginDialog @ref="loginDialog" ... />
@code {
MyLoginDialog loginDialog = default!;
void OnSomething()
{
loginDialog.Show();
}
}
Quando o componente pai é renderizado, o campo é preenchido com a instância do componente filho. Em seguida, você pode chamar métodos na instância do componente ou manipulá-la de outra forma.
Não é recomendável manipular o estado do componente diretamente usando referências de componente. Isso impede que o componente seja renderizado automaticamente na hora certa.
Capturar referências de elemento
Os componentes do Razor podem capturar referências a um elemento. Diferentemente dos controles de servidor HTML no ASP.NET Web Forms, não é possível manipular o DOM diretamente usando uma referência de elemento no Blazor. O Blazor lida com a maioria das interações de DOM por você usando seu algoritmo de comparação do DOM. As referências de elementos capturadas no Blazor são opacas. No entanto, eles são usados para transmitir uma referência de elemento específica em uma chamada de interoperabilidade JavaScript. Para saber mais sobre interoperabilidade JavaScript, confira Interoperabilidade entre JavaScript e Blazor no ASP.NET Core.
Componentes modelados
No ASP.NET Web Forms, você pode criar controles modelo. Os controles modelo permitem que o desenvolvedor especifique uma parte do HTML usada para renderizar um controle de contêiner. A mecânica da criação de controles de servidor modelo é complexa, mas permite cenários poderosos para a renderização de dados em uma maneira personalizável pelo usuário. Exemplos de controle modelo incluem Repeater
e DataList
.
Os componentes do Razor também podem virar modelo com a definição de parâmetros de componente do tipo RenderFragment
ou RenderFragment<T>
. Um RenderFragment
representa uma parte da marcação Razor que pode ser renderizada pelo componente. Um RenderFragment<T>
é uma parte da marcação Razor que usa um parâmetro que pode ser especificado quando o fragmento de renderização é renderizado.
Conteúdo filho
Os componentes do Razor podem capturar seu conteúdo filho como um RenderFragment
e renderizar esse conteúdo como parte da renderização do componente. Para capturar o conteúdo filho, defina um parâmetro de componente do tipo RenderFragment
e nomeie-o ChildContent
.
ChildContentComponent.razor
<h1>Component with child content</h1>
<div>@ChildContent</div>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}
Um componente pai pode fornecer conteúdo filho usando sintaxe Razor normal.
<ChildContentComponent>
<ChildContent>
<p>The time is @DateTime.Now</p>
</ChildContent>
</ChildContentComponent>
Parâmetros de modelo
Um componente modelo do Razor também pode definir vários parâmetros de componente do tipo RenderFragment
ou RenderFragment<T>
. O parâmetro para um RenderFragment<T>
pode ser especificado quando é invocado. Para especificar um parâmetro de tipo genérico de um componente, use a diretiva Razor @typeparam
.
SimpleListView.razor
@typeparam TItem
@Heading
<ul>
@foreach (var item in Items)
{
<li>@ItemTemplate(item)</li>
}
</ul>
@code {
[Parameter]
public RenderFragment Heading { get; set; }
[Parameter]
public RenderFragment<TItem> ItemTemplate { get; set; }
[Parameter]
public IEnumerable<TItem> Items { get; set; }
}
Ao usar um componente modelo, os parâmetros do modelo podem ser especificados usando elementos filho que correspondem aos nomes dos parâmetros. Os argumentos de componente do tipo RenderFragment<T>
transmitidos como elementos têm um parâmetro implícito denominado context
. Você pode alterar o nome desse parâmetro de implementação usando o atributo Context
no elemento filho. Qualquer parâmetro de tipo genérico pode ser especificado usando um atributo que corresponda ao nome do parâmetro de tipo. O parâmetro de tipo será inferido, se possível:
<SimpleListView Items="messages" TItem="string">
<Heading>
<h1>My list</h1>
</Heading>
<ItemTemplate Context="message">
<p>The message is: @message</p>
</ItemTemplate>
</SimpleListView>
A saída desse componente tem esta aparência:
<h1>My list</h1>
<ul>
<li><p>The message is: message1</p></li>
<li><p>The message is: message2</p></li>
<ul>
Code-behind
Normalmente, um componente do Razor é criado em um único arquivo .razor. No entanto, também é possível separar o código e a marcação usando um arquivo code-behind. Para usar um arquivo de componente, adicione um arquivo C# que corresponda ao nome do arquivo do componente, mas com uma extensão .cs adicionada (Counter.Razor.cs). Use o arquivo C# para definir uma classe base para o componente. Você pode nomear a classe base como quiser, mas é comum nomear a classe da mesma forma que a classe de componente, porém com uma Base
extensão adicionada (CounterBase
). A classe baseada em componente também precisa derivar de ComponentBase
. Em seguida, no arquivo de componente do Razor, adicione a diretiva @inherits
a fim de especificar a classe base para o componente (@inherits CounterBase
).
Counter.razor
@inherits CounterBase
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button @onclick="IncrementCount">Click me</button>
Counter.razor.cs
public class CounterBase : ComponentBase
{
protected int currentCount = 0;
protected void IncrementCount()
{
currentCount++;
}
}
A visibilidade dos membros do componente na classe base precisa ser protected
ou public
a fim de ficar visível para a classe de componente.
Recursos adicionais
O exposto acima não é um tratamento exaustivo de todos os aspectos dos componentes do Razor. Para obter mais informações sobre como Criar e usar componentes do Razor do ASP.NET Core, confira a documentação Blazor.