Componenti di ASP.NET Core Razor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Questo articolo illustra come creare e usare i componenti di Razor nelle app Blazor e offre linee guida su sintassi, denominazione dei componenti, spazi dei nomi e parametri dei componenti di Razor.

Componenti di Razor

Blazorle app vengono compilate usando Razor componenti, noti in modo informale comeBlazorcomponenti o solo componenti. Un componente è una parte autonoma dell'interfaccia utente con logica di elaborazione necessaria per abilitare il comportamento dinamico. I componenti possono essere annidati, riutilizzati, condivisi tra progetti e usati nelle app MVC e Razor Pages.

Il rendering dei componenti viene eseguito in una rappresentazione in memoria del modello DOM (Document Object Model) del browser denominata albero di rendering, usato per aggiornare l'interfaccia utente in modo flessibile ed efficiente.

Anche se "Razor componenti" condivide alcuni nomi con altre tecnologie di rendering del contenuto core ASP.NET, Razor i componenti devono essere distinti dalle diverse funzionalità seguenti in ASP.NET Core:

Classi di componenti

I componenti vengono implementati usando una combinazione di markup C# e HTML nei file dei componenti di Razor con l'estensione .razor.

Per impostazione predefinita, ComponentBase è la classe di base per i componenti descritti dai Razor file di componente. ComponentBase implementa l'astrazione più bassa dei componenti, l'interfaccia IComponent . ComponentBase definisce le proprietà e i metodi dei componenti per la funzionalità di base, ad esempio, per elaborare un set di eventi del ciclo di vita dei componenti predefiniti.

ComponentBasenell'origine dotnet/aspnetcoredi riferimento: l'origine di riferimento contiene osservazioni aggiuntive sugli eventi del ciclo di vita predefiniti. Tenere tuttavia presente che le implementazioni interne delle funzionalità dei componenti sono soggette a modifiche in qualsiasi momento senza preavviso.

Nota

I collegamenti della documentazione all'origine del riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la versione successiva di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Switch branches or tags. Per altre informazioni, vedere How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Come selezionare un tag di versione del codice sorgente di ASP.NET - dotnet/AspNetCore.Docs #26205).

Gli sviluppatori creano Razor in genere componenti da Razor file di componente (.razor) o si basano i relativi componenti su ComponentBase, ma i componenti possono anche essere compilati implementando IComponent. I componenti compilati dallo sviluppatore che implementano IComponent possono assumere un controllo di basso livello sul rendering al costo di dover attivare manualmente il rendering con eventi e metodi del ciclo di vita che lo sviluppatore deve creare e gestire.

Sintassi Razor

I componenti usano la sintassi di Razor. Due funzionalità di Razor vengono ampiamente usate dai componenti: le direttive e gli attributi delle direttive. Si tratta di parole chiave riservate con il prefisso @ visualizzate nel markup Razor:

  • Direttive: cambiano il modo in cui il markup dei componenti viene analizzato o il modo in cui funziona. Ad esempio, la direttiva @page specifica un componente instradabile con un modello di route e può essere raggiunta direttamente dalla richiesta di un utente nel browser a un URL specifico.

    Per convenzione, le direttive di un componente all'inizio di una definizione di componente (.razor file) vengono inserite in un ordine coerente. Per le direttive ripetute, le direttive vengono posizionate alfabeticamente in base allo spazio dei nomi o al tipo, ad eccezione @using delle direttive con ordinamento di secondo livello speciale.

    L'ordine seguente viene adottato dalle app di esempio e dalla Blazor documentazione. I componenti forniti da un Blazor modello di progetto possono differire dall'ordine seguente e usare un formato diverso. Ad esempio, i componenti del framework Identity includono righe vuote Blazor tra blocchi di @using direttive e blocchi di @inject direttive. È possibile usare uno schema di ordinamento personalizzato e un formato nelle proprie app.

    Documentazione e ordine di direttiva dell'app Razor di esempio:

    • @page
    • @rendermode (.NET 8 o versione successiva)
    • @using
      • System spazi dei nomi (ordine alfabetico)
      • Microsoft spazi dei nomi (ordine alfabetico)
      • Spazi dei nomi dell'API di terze parti (ordine alfabetico)
      • Spazi dei nomi dell'app (ordine alfabetico)
    • Altre direttive (ordine alfabetico)

    Nessuna riga vuota viene visualizzata tra le direttive. Viene visualizzata una riga vuota tra le direttive e la prima riga di Razor markup.

    Esempio:

    @page "/doctor-who-episodes/{season:int}"
    @rendermode InteractiveWebAssembly
    @using System.Globalization
    @using System.Text.Json
    @using Microsoft.AspNetCore.Localization
    @using Mandrill
    @using BlazorSample.Components.Layout
    @attribute [Authorize]
    @implements IAsyncDisposable
    @inject IJSRuntime JS
    @inject ILogger<DoctorWhoEpisodes> Logger
    
    <PageTitle>Doctor Who Episode List</PageTitle>
    
    ...
    
  • Attributi delle direttive: cambiano il modo in cui un elemento di un componente viene analizzato o il modo in cui funziona.

    Esempio:

    <input @bind="episodeId" />
    

    È possibile anteporre i valori degli attributi della direttiva con il simbolo@ () per le espressioni non esplicite Razor (@bind="@episodeId"), ma non è consigliabile e la documentazione non adotta l'approccio negli esempi.

Le direttive e gli attributi delle direttive usati nei componenti vengono illustrati ulteriormente in questo e in altri articoli del set di documenti su Blazor. Per informazioni generali sulla sintassi di Razor, vedere Informazioni di riferimento sulla sintassi di Razor per ASP.NET Core.

Nome del componente, nome della classe e spazio dei nomi

Il nome di un componente deve iniziare con un carattere maiuscolo:

Supportati:ProductDetail.razor

Non supportatoproductDetail.razor:

Le convenzioni di denominazione comuni di Blazor usate nella documentazione di Blazor includono:

  • I percorsi di file e i nomi di file usano la distinzione tra maiuscole e minuscole Pascal† e vengono visualizzati prima di visualizzare esempi di codice. Se è presente un percorso, indica il percorso tipico della cartella. Ad esempio, Components/Pages/ProductDetail.razor indica che il ProductDetail componente ha un nome file di ProductDetail.razor e risiede nella Pages cartella della Components cartella dell'app.
  • I percorsi dei file dei componenti per i componenti instradabili corrispondono ai relativi URL nel caso kebab++ con trattini che appaiono tra le parole nel modello di route di un componente. Ad esempio, un componente ProductDetail con un modello di route /product-detail (@page "/product-detail") viene richiesto in un browser nell'URL relativo /product-detail.

†La notazione Pascal (lettere maiuscole) è una convenzione di denominazione senza spazi e punteggiatura e con la prima lettera di ogni parola in maiuscolo, inclusa la prima parola.
*Kebab case è una convenzione di denominazione senza spazi e punteggiatura che usa lettere minuscole e trattini tra le parole.

I componenti sono classi C# comuni e possono essere inseriti ovunque all'interno di un progetto. I componenti che producono pagine Web si trovano in genere nella cartella Components/Pages. I componenti non di pagina vengono spesso inseriti nella cartella Components o in una cartella personalizzata aggiunta al progetto.

In genere, lo spazio dei nomi di un componente deriva dallo spazio dei nomi radice dell'app e dalla posizione (cartella) del componente all'interno dell'app. Se lo spazio dei nomi radice dell'app è BlazorSample e il Counter componente si trova nella cartella Components/Pages:

  • Lo spazio dei nomi del componente Counter è BlazorSample.Components.Pages.
  • Il nome di tipo completo del componente è BlazorSample.Components.Pages.Counter.

Per le cartelle personalizzate che contengono componenti, aggiungere una direttiva @using al componente padre o al file _Imports.razor dell'app. L'esempio seguente rende disponibili i componenti nella cartella AdminComponents:

@using BlazorSample.AdminComponents

Nota

Le direttive @using nel file _Imports.razor vengono applicate solo ai file Razor files (.razor), non ai file C# (.cs).

Le istruzioni con using alias sono supportate. Nell'esempio seguente la classe pubblica WeatherForecast del GridRendering componente viene resa disponibile come WeatherForecast in un componente altrove nell'app:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

È anche possibile fare riferimento ai componenti usando i nomi completi, che non richiedono una direttiva @using. L'esempio seguente fa riferimento direttamente al componente ProductDetail nella cartella AdminComponents/Pages dell'app:

<BlazorSample.AdminComponents.Pages.ProductDetail />

Lo spazio dei nomi di un componente creato con Razor è basato su quanto segue (in ordine di priorità):

  • Direttiva @namespace nel markup del file Razor (ad esempio, @namespace BlazorSample.CustomNamespace).
  • RootNamespace del progetto file di progetto (ad esempio, <RootNamespace>BlazorSample</RootNamespace>).
  • Spazio dei nomi del progetto e percorso dalla radice del progetto al componente. Ad esempio, il framework viene {PROJECT NAMESPACE}/Components/Pages/Home.razor risolto con uno spazio dei nomi del progetto di BlazorSample nello spazio dei nomi BlazorSample.Components.Pages per il Home componente. {PROJECT NAMESPACE} è lo spazio dei nomi del progetto. I componenti seguono le regole di associazione dei nomi C#. Per il Home componente in questo esempio, i componenti nell'ambito sono tutti i componenti:
    • Nella stessa cartella, Components/Pages.
    • I componenti nella radice del progetto che non specificano in modo esplicito uno spazio dei nomi diverso.

Non sono supportati:

  • Qualificazione global::.
  • Nomi parziali. Non è ad esempio possibile aggiungere @using BlazorSample.Components a un componente e quindi fare riferimento al componente NavMenu nella cartella Components/Layout dell'app (Components/Layout/NavMenu.razor) con <Layout.NavMenu></Layout.NavMenu>.

Il nome di un componente deve iniziare con un carattere maiuscolo:

Supportati:ProductDetail.razor

Non supportatoproductDetail.razor:

Le convenzioni di denominazione comuni di Blazor usate nella documentazione di Blazor includono:

  • I percorsi di file e i nomi di file usano la distinzione tra maiuscole e minuscole Pascal† e vengono visualizzati prima di visualizzare esempi di codice. Se è presente un percorso, indica il percorso tipico della cartella. Ad esempio, Pages/ProductDetail.razor indica che il componente ProductDetail ha il nome file ProductDetail.razor e si trova nella cartella Pages dell'app.
  • I percorsi dei file dei componenti per i componenti instradabili corrispondono ai relativi URL nel caso kebab++ con trattini che appaiono tra le parole nel modello di route di un componente. Ad esempio, un componente ProductDetail con un modello di route /product-detail (@page "/product-detail") viene richiesto in un browser nell'URL relativo /product-detail.

†La notazione Pascal (lettere maiuscole) è una convenzione di denominazione senza spazi e punteggiatura e con la prima lettera di ogni parola in maiuscolo, inclusa la prima parola.
*Kebab case è una convenzione di denominazione senza spazi e punteggiatura che usa lettere minuscole e trattini tra le parole.

I componenti sono classi C# comuni e possono essere inseriti ovunque all'interno di un progetto. I componenti che producono pagine Web si trovano in genere nella cartella Pages. I componenti non di pagina vengono spesso inseriti nella cartella Shared o in una cartella personalizzata aggiunta al progetto.

In genere, lo spazio dei nomi di un componente deriva dallo spazio dei nomi radice dell'app e dalla posizione (cartella) del componente all'interno dell'app. Se lo spazio dei nomi radice dell'app è BlazorSample e il Counter componente si trova nella cartella Pages:

  • Lo spazio dei nomi del componente Counter è BlazorSample.Pages.
  • Il nome di tipo completo del componente è BlazorSample.Pages.Counter.

Per le cartelle personalizzate che contengono componenti, aggiungere una direttiva @using al componente padre o al file _Imports.razor dell'app. L'esempio seguente rende disponibili i componenti nella cartella AdminComponents:

@using BlazorSample.AdminComponents

Nota

Le direttive @using nel file _Imports.razor vengono applicate solo ai file Razor files (.razor), non ai file C# (.cs).

Le istruzioni con using alias sono supportate. Nell'esempio seguente la classe pubblica WeatherForecast del GridRendering componente viene resa disponibile come WeatherForecast in un componente altrove nell'app:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

È anche possibile fare riferimento ai componenti usando i nomi completi, che non richiedono una direttiva @using. L'esempio seguente fa riferimento direttamente al componente ProductDetail nella cartella Components dell'app:

<BlazorSample.Components.ProductDetail />

Lo spazio dei nomi di un componente creato con Razor è basato su quanto segue (in ordine di priorità):

  • Direttiva @namespace nel markup del file Razor (ad esempio, @namespace BlazorSample.CustomNamespace).
  • RootNamespace del progetto file di progetto (ad esempio, <RootNamespace>BlazorSample</RootNamespace>).
  • Spazio dei nomi del progetto e percorso dalla radice del progetto al componente. Ad esempio, il framework viene {PROJECT NAMESPACE}/Pages/Index.razor risolto con uno spazio dei nomi del progetto di BlazorSample nello spazio dei nomi BlazorSample.Pages per il Index componente. {PROJECT NAMESPACE} è lo spazio dei nomi del progetto. I componenti seguono le regole di associazione dei nomi C#. Per il Index componente in questo esempio, i componenti nell'ambito sono tutti i componenti:
    • Nella stessa cartella, Pages.
    • I componenti nella radice del progetto che non specificano in modo esplicito uno spazio dei nomi diverso.

Non sono supportati:

  • Qualificazione global::.
  • Nomi parziali. Non è ad esempio possibile aggiungere @using BlazorSample a un componente e quindi fare riferimento al componente NavMenu nella cartella Shared dell'app (Shared/NavMenu.razor) con <Shared.NavMenu></Shared.NavMenu>.

Supporto di classi parziali

I componenti vengono generati come classi parziali C# e vengono creati usando uno dei due approcci seguenti:

  • Un singolo file contiene codice C# definito in uno o più blocchi @code, markup HTML e markup Razor. I modelli di progetto Blazor definiscono i componenti usando questo approccio basato su un file singolo.
  • I markup HTML e Razor vengono inseriti in un file Razor (.razor). Il codice C# viene inserito in un file code-behind definito come classe parziale (.cs).

Nota

Un foglio di stile del componente che definisce gli stili specifici del componente è un file separato (.css). L'isolamento CSS di Blazor viene descritto più avanti in Isolamento CSS di ASP.NET Core Blazor.

L'esempio seguente mostra il componente Counter predefinito con un blocco @code in un'app generata da un modello di progetto Blazor. Il markup e il codice C# si trovano nello stesso file. Questo è l'approccio più comune adottato nella creazione di componenti.

Counter.razor:

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Il componente seguente Counter suddivide il codice HTML e Razor il markup della presentazione dal codice C# usando un file code-behind con una classe parziale. La suddivisione del markup dal codice C# è favorita da alcune organizzazioni e sviluppatori per organizzare il codice del componente in base al modo in cui preferiscono lavorare. Ad esempio, l'esperto dell'interfaccia utente dell'organizzazione può lavorare sul livello di presentazione indipendentemente da un altro sviluppatore che lavora sulla logica C# del componente. L'approccio è utile anche quando si lavora con codice o generatori di origine generati automaticamente. Per altre informazioni, vedere Classi e metodi parziali (Guida per programmatori C#).

CounterPartialClass.razor:

@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

CounterPartialClass.razor.cs:

namespace BlazorSample.Components.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
namespace BlazorSample.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
namespace BlazorSample.Pages
{
    public partial class CounterPartialClass
    {
        private int currentCount = 0;

        private void IncrementCount()
        {
            currentCount++;
        }
    }
}

Le direttive @using nel file _Imports.razor vengono applicate solo ai file Razor files (.razor), non ai file C# (.cs). Aggiungere spazi dei nomi a un file di classe parziale in base alle esigenze.

Spazi dei nomi tipici usati dai componenti:

using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Sections
using Microsoft.AspNetCore.Components.Web;
using static Microsoft.AspNetCore.Components.Web.RenderMode;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;

Gli spazi dei nomi tipici includono anche lo spazio dei nomi dell'app e lo spazio dei nomi corrispondente alla cartella Components dell'app:

using BlazorSample;
using BlazorSample.Components;

È anche possibile includere cartelle aggiuntive, ad esempio la Layout cartella :

using BlazorSample.Components.Layout;
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;

Gli spazi dei nomi tipici includono anche lo spazio dei nomi dell'app e lo spazio dei nomi corrispondente alla cartella Shared dell'app:

using BlazorSample;
using BlazorSample.Shared;
using System.Net.Http;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;

Gli spazi dei nomi tipici includono anche lo spazio dei nomi dell'app e lo spazio dei nomi corrispondente alla cartella Shared dell'app:

using BlazorSample;
using BlazorSample.Shared;

Specificare una classe base

La direttiva @inherits viene usata per specificare una classe di base per un componente. A differenza dell'uso di classi parziali, che separano solo il markup dalla logica C#, l'uso di una classe base consente di ereditare il codice C# da usare in un gruppo di componenti che condividono le proprietà e i metodi della classe base. L'uso delle classi di base riduce la ridondanza del codice nelle app e risulta utile quando si fornisce codice di base da librerie di classi a più app. Per altre informazioni, vedere Ereditarietà in C# e .NET.

Nell'esempio seguente la BlazorRocksBase1 classe base deriva da ComponentBase.

BlazorRocks1.razor:

@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>

BlazorRocksBase1.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}

Definizione dei percorsi di trasferimento

Il routing in Blazor si ottiene fornendo un modello di route a ogni componente accessibile nell'app con una direttiva @page. Quando viene compilato un file Razor con una direttiva @page, alla classe generata viene assegnata una valore RouteAttribute che specifica il modello di route. In fase di esecuzione, il router cerca le classi di componenti con una classe RouteAttribute ed esegue il rendering di qualsiasi componente abbia un modello di route corrispondente all'URL richiesto.

Il componente seguente HelloWorld usa un modello di route di /hello-worlde viene raggiunta la pagina Web sottoposta a rendering per il componente all'URL /hello-worldrelativo .

HelloWorld.razor:

@page "/hello-world"

<PageTitle>Hello World!</PageTitle>

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>

Il componente precedente viene caricato nel browser all'indirizzo /hello-world indipendentemente dal fatto che si aggiunga o meno il componente al riquadro di spostamento dell'interfaccia utente dell'app. Facoltativamente, i componenti possono essere aggiunti al componente NavMenu in modo che un collegamento al componente venga visualizzato nel riquadro di spostamento basato sull'interfaccia utente dell'app.

Per il componente precedente HelloWorld , è possibile aggiungere un NavLink componente al NavMenu componente. Per altre informazioni, incluse le descrizioni dei componenti NavLink e NavMenu, vedere Routing ed esplorazione di Blazor ASP.NET Core.

Markup

L'interfaccia utente di un componente viene definita usando la sintassi di Razor, costituita da markup Razor, C# e HTML. Quando un'app viene compilata, il markup HTML e la logica di rendering C# vengono convertiti in una classe del componente. Il nome della classe generata corrisponde al nome del file.

I membri della classe del componente vengono definiti in uno o più blocchi @code. Nei blocchi @code blocchi lo stato del componente viene specificato ed elaborato con C#:

  • Inizializzatori di proprietà e di campo.
  • Valori dei parametri degli argomenti passati dai componenti padre e dai parametri delle route.
  • Metodi per la gestione degli eventi utente, gli eventi del ciclo di vita e la logica del componente personalizzata.

I membri del componente vengono usati nella logica di rendering usando espressioni C# che iniziano con il simbolo @. Ad esempio, il rendering di un campo C# viene eseguito anteponendo @ al nome del campo. Il componente Markup seguente esegue la valutazione e il rendering di:

  • headingFontStyle per il valore della proprietà CSS font-style dell'elemento intestazione.
  • headingText per il contenuto dell'elemento intestazione.

Markup.razor:

@page "/markup"

<PageTitle>Markup</PageTitle>

<h1>Markup Example</h1>

<h2 style="font-style:@headingFontStyle">@headingText</h2>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}

Nota

Gli esempi presenti nella documentazione di Blazor specificano il modificatore di accesso private per i membri privati. I membri privati hanno come ambito la classe di un componente. Tuttavia, C# presume il modificatore di accesso private quando non è presente alcun modificatore di accesso, quindi contrassegnare in modo esplicito i membri "private" nel codice è facoltativo. Per altre informazioni sui modificatori di accesso, vedere Modificatori di accesso (guida per i programmatori C#).

Il Blazor framework elabora internamente un componente come albero di rendering, che è la combinazione di DOM e CSSOM (Cascading Style Sheet Object Model) di un componente. Dopo il rendering iniziale del componente, l'albero di rendering del componente viene rigenerato in risposta agli eventi. Blazor confronta il nuovo albero di rendering con quello precedente e applica eventuali modifiche al modello DOM del browser per la visualizzazione. Per altre informazioni, vedere Rendering dei componenti di ASP.NET CoreRazor.

La sintassi di Razor per le strutture di controllo, le direttive e gli attributi delle direttive C# è in minuscolo (esempi: @if, @code, @bind). I nomi delle proprietà sono in maiuscolo (esempio: @Body per LayoutComponentBase.Body).

I metodi asincroni (async) non supportano la restituzione di void

Il framework Blazor non tiene traccia dei metodi asincroni che restituiscono void (async). Di conseguenza, le eccezioni non vengono rilevate se viene restituito void. Restituire sempre una classe Task dai metodi asincroni.

Componenti annidati

I componenti possono includere altri componenti dichiarandoli tramite la sintassi HTML. Il markup per l'uso di un componente è simile a un tag HTML, in cui il nome del tag è il tipo di componente.

Si consideri il componente Heading seguente, che può essere usato da altri componenti per visualizzare un'intestazione.

Heading.razor:

<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}

Il markup seguente nel componente HeadingExample esegue il rendering del componente Heading precedente nella posizione in cui viene visualizzato il tag <Heading />.

HeadingExample.razor:

@page "/heading-example"

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />

Se un componente contiene un elemento HTML con la prima lettera maiuscola che non corrisponde al nome di un componente all'interno dello stesso spazio dei nomi, viene generato un avviso che indica che l'elemento ha un nome imprevisto. L'aggiunta di una direttiva @using per lo spazio dei nomi del componente rende disponibile il componente, risolvendo l'avviso. Per altre informazioni, vedere la sezione Nome componente, nome della classe e spazio dei nomi .

L'esempio del componente Heading illustrato in questa sezione non ha una direttiva @page, quindi il componente Heading non è direttamente accessibile per un utente tramite una richiesta diretta nel browser. Tuttavia, qualsiasi componente con una direttiva @page può essere annidato in un altro componente. Se il componente Heading è stato reso accessibile direttamente includendo @page "/heading" all'inizio del file Razor, il rendering del componente verrà eseguito per le richieste del browser sia in /heading che in /heading-example.

Parametri del componente

I parametri del componente passano i dati ai componenti e vengono definiti usando proprietà C# pubbliche nel classe del componente con l'attributo [Parameter]. Nell'esempio seguente un tipo riferimento predefinito (System.String) e un tipo riferimento definito dall'utente (PanelBody) vengono passati come parametri del componente.

PanelBody.cs:

namespace BlazorSample;

public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string Text { get; set; }
    public string Style { get; set; }
}
public class PanelBody
{
    public string Text { get; set; }
    public string Style { get; set; }
}

ParameterChild.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new PanelBody()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}

Avviso

È possibile fornire i valori iniziali per i parametri del componente, ma non creare un componente che scriva nei propri parametri dopo il primo rendering del componente. Per altre informazioni, vedere Evitare la sovrascrittura dei parametri in ASP.NET Core Blazor.

I parametri Title e Body del componente ParameterChild vengono impostati dagli argomenti nel tag HTML che esegue il rendering dell'istanza del componente. Il componente ParameterParent seguente esegue il rendering di due componenti ParameterChild:

  • Il rendering del primo componente ParameterChild viene eseguito senza fornire argomenti per i parametri.
  • Il secondo componente ParameterChild riceve i valori per Title e Body dal componente ParameterParent, che usa un'espressione C# esplicita per impostare i valori delle proprietà di PanelBody.

Parameter1.razor:

@page "/parameter-1"

<PageTitle>Parameter 1</PageTitle>

<h1>Parameter Example 1</h1>

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

Il markup HTML sottoposto a rendering seguente dal componente ParameterParent mostra i valori predefiniti del componente ParameterChild quando il componente ParameterParent non fornisce i valori dei parametri del componente. Quando il componente ParameterParent fornisce i valori dei parametri del componente, questi sostituiscono i valori predefiniti del componente ParameterChild.

Nota

Per maggiore chiarezza, le classi di stile CSS sottoposte a rendering non vengono visualizzate nel markup HTML sottoposto a rendering seguente.

<h1>Child component (without attribute values)</h1>

<div>
    <div>Set By Child</div>
    <div>Set by child.</div>
</div>

<h1>Child component (with attribute values)</h1>

<div>
    <div>Set by Parent</div>
    <div>Set by parent.</div>
</div>

Assegnare un campo, una proprietà o un risultato C# a un parametro del componente come valore dell'attributo HTML. Il valore dell'attributo può in genere essere qualsiasi espressione C# corrispondente al tipo del parametro. Il valore dell'attributo può facoltativamente portare con un Razor simbolo riservato@, ma non è obbligatorio.

Se il parametro del componente è di tipo string, il valore dell'attributo viene invece considerato come valore letterale stringa C# per impostazione predefinita. Se invece si vuole specificare un'espressione C#, usare il @ prefisso .

Il componente ParameterParent2 seguente visualizza quattro istanze del componente ParameterChild precedente e ne imposta i valori del parametro Title su:

Le virgolette attorno ai valori degli attributi dei parametri sono facoltative nella maggior parte dei casi in base alla specifica HTML5. Ad esempio, Value=this invece di Value="this" è supportato. È tuttavia consigliabile usare le virgolette perché consentono di ricordare più facilmente i valori e sono ampiamente adottate nelle tecnologie basate sul Web.

In tutta la documentazione, gli esempi di codice:

  • Usano sempre le virgolette. Esempio: Value="this".
  • Non usare il @ prefisso con caratteri nonliterali, a meno che non sia necessario. Esempio: Count="ct", dove ct è una variabile tipizzata da numeri. Count="@ct" è un approccio stilistico valido, ma la documentazione e gli esempi non adottano la convenzione.
  • Evitare @ sempre valori letterali, all'esterno delle Razor espressioni. Esempio: IsFixed="true". Sono incluse le parole chiave (ad esempio , this) e null, ma è possibile scegliere di usarle se lo si desidera. Ad esempio, IsFixed="@true" è insolito, ma supportato.

Parameter2.razor:

@page "/parameter-2"

<PageTitle>Parameter 2</PageTitle>

<h1>Parameter Example 2</h1>

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new PanelData();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

Nota

Quando si assegna un membro C# a un parametro del componente, non anteporre l'attributo HTML del parametro con @.

Corretto (Title è un parametro stringa, Count è un parametro tipizzato da numero):

<ParameterChild Title="@title" Count="ct" />
<ParameterChild Title="@title" Count="@ct" />

Risposta errata:

<ParameterChild @Title="@title" @Count="ct" />
<ParameterChild @Title="@title" @Count="@ct" />

Diversamente dalle pagine di Razor (.cshtml), Blazor non può eseguire operazioni asincrone in un'espressione Razor durante il rendering di un componente perché Blazor è progettato per il rendering di interfacce utente interattive. In un'interfaccia utente interattiva, nella schermata deve sempre essere visibile qualcosa, quindi non ha senso bloccare il flusso di rendering. Le operazioni asincrone vengono invece eseguite durante uno degli eventi asincroni del ciclo di vita. Dopo ogni evento asincrono del ciclo di vita, il componente può eseguire di nuovo il rendering. La sintassi di Razor seguente non è supportata:

<ParameterChild Title="@await ..." />

Il codice nell'esempio precedente genera un errore del compilatore quando viene compilata l'app:

L'operatore "await" può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore "async" e di modificarne il tipo restituito in "Task".

Per ottenere in modo asincrono un valore per il parametro Title nell'esempio precedente, il componente può usare l'evento del ciclo di vita OnInitializedAsync, come illustrato nell'esempio seguente:

<ParameterChild Title="@title" />

@code {
    private string? title;
    
    protected override async Task OnInitializedAsync()
    {
        title = await ...;
    }
}

Per altre informazioni, vedere Ciclo di vita dei componenti di ASP.NET Core Razor.

L'uso di un'espressione Razor esplicita per concatenare il testo con un risultato dell'espressione per l'assegnazione a un parametro non è supportato. L'esempio seguente cerca di concatenare il testo "Set by " con il valore della proprietà di un oggetto. Anche se questa sintassi è supportata in una pagina Razor (.cshtml), non è valida per l'assegnazione al parametro Title dell'elemento figlio in un componente. La sintassi di Razor seguente non è supportata:

<ParameterChild Title="Set by @(panelData.Title)" />

Il codice nell'esempio precedente genera un errore del compilatore quando viene compilata l'app:

Gli attributi dei componenti non supportano contenuto complesso (C# e markup misto).

Per supportare l'assegnazione di un valore composto, usare un metodo, un campo o una proprietà. L'esempio seguente esegue la concatenazione di "Set by " e il valore della proprietà di un oggetto nel metodo C# GetTitle:

Parameter3.razor:

@page "/parameter-3"

<PageTitle>Parameter 3</PageTitle>

<h1>Parameter Example 3</h1>

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new PanelData();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

Per altre informazioni, vedere Informazioni di riferimento sulla sintassi di Razor per ASP.NET Core.

Avviso

È possibile fornire i valori iniziali per i parametri del componente, ma non creare un componente che scriva nei propri parametri dopo il primo rendering del componente. Per altre informazioni, vedere Evitare la sovrascrittura dei parametri in ASP.NET Core Blazor.

I parametri del componente devono essere dichiarati come proprietà automatiche, ovvero non devono contenere logica personalizzata nelle funzioni di accesso get o set. Ad esempio, la proprietà StartData seguente è una proprietà automatica:

[Parameter]
public DateTime StartData { get; set; }

Non inserire la logica personalizzata nella funzione di accesso get o set perché i parametri del componente sono destinati esclusivamente all'uso come canale per il flusso delle informazioni da un componente padre a un componente figlio. Se una funzione di accesso set di una proprietà del componente figlio contiene la logica che causa il rerendering del componente padre, viene restituito un ciclo di rendering infinito.

Per trasformare un valore di parametro ricevuto:

  • Lasciare la proprietà del parametro come proprietà automatica per rappresentare i dati non elaborati forniti.
  • Creare una proprietà o un metodo diverso per specificare i dati trasformati in base alla proprietà del parametro.

Eseguire l'override di OnParametersSetAsync per trasformare un parametro ricevuto ogni volta che vengono ricevuti nuovi dati.

La scrittura di un valore iniziale in un parametro del componente è supportata perché le assegnazioni dei valori iniziali non interferiscono con il rendering automatico del componente di Blazor. L'assegnazione seguente della struttura DateTime locale corrente con DateTime.Now a StartData è una sintassi valida in un componente:

[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;

Dopo l'assegnazione iniziale di DateTime.Now, non assegnare un valore a StartData nel codice per gli sviluppatori. Per altre informazioni, vedere Evitare la sovrascrittura dei parametri in ASP.NET Core Blazor.

Applicare l'attributo [EditorRequired] per specificare un parametro del componente obbligatorio. Se non viene specificato un valore del parametro, negli editor o negli strumenti di compilazione possono essere visualizzati avvisi per l'utente. Questo attributo è valido solo per le proprietà contrassegnate anche con l'l'attributo [Parameter]. La classe EditorRequiredAttribute viene applicata in fase di progettazione e quando viene compilata l'app. L'attributo non viene applicato in fase di esecuzione e non garantisce un valore del parametro non null.

[Parameter]
[EditorRequired]
public string? Title { get; set; }

Sono supportati anche gli elenchi di attributi a riga singola:

[Parameter, EditorRequired]
public string? Title { get; set; }

Non usare il modificatore o init la required funzione di accesso nelle proprietà dei parametri del componente. I componenti vengono in genere creati e assegnati valori di parametro tramite reflection, che ignora le garanzie che init e required sono progettate per effettuare. Usare invece l'attributo [EditorRequired] per specificare un parametro di componente obbligatorio.

Non usare la funzione di accesso per le proprietà dei parametri del componente perché l'impostazione dei valori dei parametri del componente con ParameterView.SetParameterProperties usa la init reflection, che ignora la restrizione setter solo init. Usare l'attributo [EditorRequired] per specificare un parametro del componente obbligatorio.

Gli oggetti Tuples (documentazione API) sono supportati per i parametri dei componenti e i tipi RenderFragment. L'esempio di parametro del componente seguente passa tre valori in un oggetto Tuple:

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<PageTitle>Render Tuple Parent</PageTitle>

<h1>Render Tuple Parent Example</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

Le tuple denominate sono supportate, come illustrato nell'esempio seguente:

NamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

NamedTuples.razor:

@page "/named-tuples"

<PageTitle>Named Tuples</PageTitle>

<h1>Named Tuples Example</h1>

<NamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Quote ©2005 Universal Pictures: Serenity (Nathan Fillion)

Gli oggetti Tuples (documentazione API) sono supportati per i parametri dei componenti e i tipi RenderFragment. L'esempio di parametro del componente seguente passa tre valori in un oggetto Tuple:

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<h1>Render Tuple Parent</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

Le tuple denominate sono supportate, come illustrato nell'esempio seguente:

RenderNamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

RenderNamedTupleParent.razor:

@page "/render-named-tuple-parent"

<h1>Render Named Tuple Parent</h1>

<RenderNamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Quote ©2005 Universal Pictures: Serenity (Nathan Fillion)

Parametri di route

I componenti possono specificare i parametri di route nel modello di route della direttiva @page. Il router di Blazor usa i parametri di route per popolare i parametri dei componenti corrispondenti.

RouteParameter1.razor:

@page "/route-parameter-1/{text}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

<p>Blazor is @Text!</p>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}

Per altre informazioni, vedere la sezione Parametri di route di ASP.NET routing e navigazione coreBlazor. I parametri di route facoltativi sono supportati e trattati nella stessa sezione. Per informazioni sui parametri di route catch-all ({*pageRoute}), che acquisiscono i percorsi tra più limiti di cartella, vedere la sezione Parametri di route catch-all di ASP.NET routing e navigazione coreBlazor.

Per altre informazioni, vedere la sezione Parametri di route di ASP.NET routing e navigazione coreBlazor. I parametri di route facoltativi non sono supportati, quindi sono necessarie due @page direttive (vedere la sezione Parametri di route per altre informazioni). Per informazioni sui parametri di route catch-all ({*pageRoute}), che acquisiscono i percorsi tra più limiti di cartella, vedere la sezione Parametri di route catch-all di ASP.NET routing e navigazione coreBlazor.

Avviso

Con la compressione, abilitata per impostazione predefinita, evitare di creare componenti interattivi interattivi (autenticati/autorizzati) che eseguono il rendering dei dati da origini non attendibili. Le origini non attendibili includono parametri di route, stringhe di query, dati di JS interoperabilità e qualsiasi altra origine di dati che un utente di terze parti può controllare (database, servizi esterni). Per altre informazioni, vedere linee guida ASP.NET Core BlazorSignalR e Linee guida per la mitigazione delle minacce per ASP.NET rendering lato server interattivo CoreBlazor.

Frammenti di rendering del contenuto figlio

I componenti possono impostare il contenuto di un altro componente. Il componente che esegue l'assegnazione fornisce il contenuto tra i tag di apertura e chiusura del componente figlio.

Nell'esempio seguente il componente RenderFragmentChild ha un parametro del componente ChildContent che rappresenta un segmento dell'interfaccia utente di cui eseguire il rendering come RenderFragment. La posizione di ChildContent nel markup Razor del componente è il punto in cui viene eseguito il rendering del contenuto nell'output HTML finale.

RenderFragmentChild.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

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

Importante

Per convenzione, la proprietà che riceve il contenuto di RenderFragment deve essere denominata ChildContent.

I callback degli eventi non sono supportati per RenderFragment.

Il componente seguente fornisce contenuto per il rendering RenderFragmentChild di inserendo il contenuto all'interno dei tag di apertura e chiusura del componente figlio.

RenderFragments.razor:

@page "/render-fragments"

<PageTitle>Render Fragments</PageTitle>

<h1>Render Fragments Example</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

Dato il modo in cui Blazor esegue il rendering del contenuto figlio, il rendering dei componenti all'interno di un ciclo for richiede una variabile di indice locale se la variabile di incremento del ciclo viene usata nel contenuto del componente RenderFragmentChild. L'esempio seguente può essere aggiunto al componente padre precedente:

<h1>Three children with an index variable</h1>

@for (int c = 0; c < 3; c++)
{
    var current = c;

    <RenderFragmentChild>
        Count: @current
    </RenderFragmentChild>
}

In alternativa, usare un ciclo foreach con Enumerable.Range invece di un ciclo for. L'esempio seguente può essere aggiunto al componente padre precedente:

<h1>Second example of three children with an index variable</h1>

@foreach (var c in Enumerable.Range(0,3))
{
    <RenderFragmentChild>
        Count: @c
    </RenderFragmentChild>
}

I frammenti di rendering vengono usati per eseguire il rendering del contenuto figlio in tutte le app Blazor e sono descritti con esempi negli articoli e nelle sezioni di articolo seguenti:

Nota

I componenti di Razor predefiniti del framework Blazor usano la stessa convenzione dei parametri del componente ChildContent per impostare il contenuto. È possibile visualizzare i componenti che impostano il contenuto figlio cercando il nome ChildContent della proprietà dei parametri del componente nella documentazione dell'API (filtrare l'API in base al termine di ricerca "ChildContent").

Eseguire il rendering dei frammenti per la logica di rendering riutilizzabile

È possibile escludere i componenti figlio esclusivamente come un modo per riutilizzare la logica di rendering. Nel blocco @code di qualsiasi componente definire un delegato RenderFragment ed eseguire il rendering del frammento da qualsiasi posizione quante volte è necessario:

@RenderWelcomeInfo

<p>Render the welcome info a second time:</p>

@RenderWelcomeInfo

@code {
    private RenderFragment RenderWelcomeInfo =  @<p>Welcome to your new app!</p>;
}

Per altre informazioni, vedere Riutilizzare la logica di rendering.

Acquisire i riferimenti ai componenti

I riferimenti ai componenti consentono di fare riferimento a un'istanza di un componente per l'esecuzione dei comandi. Per acquisire un riferimento a un componente:

  • Aggiungere un attributo @ref al componente figlio.
  • Definire un campo con lo stesso tipo del componente figlio.

Quando viene eseguito il rendering del componente, il campo viene popolato con l'istanza del componente. È quindi possibile richiamare i metodi .NET sull'istanza.

Si consideri il componente ReferenceChild seguente che registra un messaggio quando viene chiamato ChildMethod.

ReferenceChild.razor:

@inject ILogger<ReferenceChild> Logger

@if (value > 0)
{
    <p>
        <code>value</code>: @value
    </p>
}

@code {
    private int value;

    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);

        this.value = value;
        StateHasChanged();
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}

Un riferimento a un componente viene popolato solo dopo che è stato eseguito il rendering del componente e l'output include l'elemento di ReferenceChild. Prima del rendering del componente, non c'è nulla a cui fare riferimento. Non tentare di chiamare direttamente un metodo componente a cui si fa riferimento a un gestore eventi , @onclick="childComponent!.ChildMethod(5)"ad esempio , perché la variabile di riferimento potrebbe non essere assegnata al momento dell'assegnazione dell'evento Click.

Per modificare i riferimenti al componente dopo che il componente ha completato il rendering, usare i metodi OnAfterRender o OnAfterRenderAsync.

Nell'esempio seguente viene utilizzato il componente precedente ReferenceChild .

ReferenceParent.razor:

@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}

Anche se per l'acquisizione dei riferimenti ai componenti si usa una sintassi simile a quella per l'acquisizione dei riferimenti agli elementi, l'acquisizione dei riferimenti ai componenti non è una funzionalità di interoperabilità JavaScript. I riferimenti ai componenti non vengono passati al codice JavaScript. I riferimenti ai componenti vengono usati solo nel codice .NET.

Importante

Non usare i riferimenti ai componenti per modificare lo stato dei componenti figlio. Usare invece i normali parametri dichiarativi dei componenti per passare i dati ai componenti figlio. L'uso dei parametri dei componenti fa in modo che i componenti figlio rieseguano automaticamente il rendering nei momenti corretti. Per altre informazioni, vedere la sezione relativa ai parametri del componente e l'articolo Associazione dati di ASP.NET Core Blazor.

Applicare un attributo

Gli attributi possono essere applicati ai componenti con la direttiva @attribute. L'esempio seguente applica l'attributo [Authorize] alla classe del componente:

@page "/"
@attribute [Authorize]

Attributi degli elementi HTML condizionali

Le proprietà degli attributi degli elementi HTML vengono impostate in modo condizionale in base al valore .NET. Se il valore è false o null, la proprietà non viene impostata. Se il valore è true, la proprietà viene impostata.

Nell'esempio seguente IsCompleted determina se la proprietà checked dell'elemento <input> viene impostata.

ConditionalAttribute.razor:

@page "/conditional-attribute"

<PageTitle>Conditional Attribute</PageTitle>

<h1>Conditional Attribute Example</h1>

<label>
    <input type="checkbox" checked="@IsCompleted" />
    Is Completed?
</label>

<button @onclick="@(() => IsCompleted = !IsCompleted)">
    Change IsCompleted
</button>

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}
@page "/conditional-attribute"

<label>
    <input type="checkbox" checked="@IsCompleted" />
    Is Completed?
</label>

<button @onclick="@(() => IsCompleted = !IsCompleted)">
    Change IsCompleted
</button>

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}
@page "/conditional-attribute"

<label>
    <input type="checkbox" checked="@IsCompleted" />
    Is Completed?
</label>

<button @onclick="@(() => IsCompleted = !IsCompleted)">
    Change IsCompleted
</button>

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}
@page "/conditional-attribute"

<label>
    <input type="checkbox" checked="@IsCompleted" />
    Is Completed?
</label>

<button @onclick="@(() => IsCompleted = !IsCompleted)">
    Change IsCompleted
</button>

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}
@page "/conditional-attribute"

<label>
    <input type="checkbox" checked="@IsCompleted" />
    Is Completed?
</label>

<button @onclick="@(() => IsCompleted = !IsCompleted)">
    Change IsCompleted
</button>

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}

Per altre informazioni, vedere Informazioni di riferimento sulla sintassi di Razor per ASP.NET Core.

Avviso

Alcuni attributi HTML, ad esempio aria-pressed, non funzionano correttamente quando il tipo .NET è bool. In questi casi, usare un tipo string invece di un tipo bool.

HTML non elaborato

Il rendering delle stringhe viene in genere eseguito usando i nodi di testo DOM, il che significa che qualsiasi markup in essi contenuto viene ignorato e considerato come testo letterale. Per eseguire il rendering di codice HTML non elaborato, eseguire il wrapping del contenuto HTML in un valore MarkupString. Il valore viene analizzato come HTML o SVG e inserito nel nodo DOM.

Avviso

Il rendering di contenuto HTML non elaborato costruito da qualsiasi origine non attendibile è un rischio per la sicurezza ed è sempre meglio evitarlo.

L'esempio seguente mostra l'uso del tipo MarkupString per aggiungere un blocco di contenuto HTML statico all'output sottoposto a rendering di un componente.

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

Modelli di Razor

È possibile definire frammenti di rendering usando la sintassi dei modelli di Razor per definire un frammento di interfaccia utente. I modelli di Razor usano il formato seguente:

@<{HTML tag}>...</{HTML tag}>

L'esempio seguente illustra come specificare i valori RenderFragment e RenderFragment<TValue> e come eseguire il rendering dei modelli direttamente in un componente. I frammenti di rendering possono essere passati anche come argomenti ai componenti basati su modelli.

RazorTemplate.razor:

@page "/razor-template"

<PageTitle>Razor Template</PageTitle>

<h1>Razor Template Example</h1>

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string Name { get; set; }
    }
}

Output sottoposto a rendering del codice precedente:

<p>The time is 4/19/2021 8:54:46 AM.</p>
<p>Pet: Nutty Rex</p>

Asset statici

Blazor segue la convenzione delle app ASP.NET Core per gli asset statici. Gli asset statici si trovano nella cartella web root (wwwroot) del progetto o nelle cartelle sotto la cartella wwwroot.

Usare un percorso relativo alla base (/) per fare riferimento alla radice Web per un asset statico. Nell'esempio seguente logo.png si trova fisicamente nella cartella {PROJECT ROOT}/wwwroot/images. {PROJECT ROOT} è la radice del progetto dell'app.

<img alt="Company logo" src="/images/logo.png" />

I componenti non supportano la notazione con tilde-barra (~/).

Per informazioni sull'impostazione del percorso di base di un'app, vedere Ospitare e distribuire ASP.NET Core Blazor.

Gli helper tag non sono supportati nei componenti

Gli oggetti Tag Helpers non sono supportati nei componenti. Per fornire funzionalità di tipo helper tag in Blazor, creare un componente con le stesse funzionalità dell'helper tag e usare invece il componente.

Immagini SVG (Scalable Vector Graphics)

Poiché Blazor esegue il rendering di contenuti HTML, le immagini supportate dal browser, incluse le immagini SVG (Scalable Vector Graphics) (.svg), sono supportate tramite il tag <img>:

<img alt="Example image" src="image.svg" />

Analogamente, le immagini SVG sono supportate nelle regole CSS di un file di foglio di stile (.css):

.element-class {
    background-image: url("image.svg");
}

Blazor supporta l'elemento <foreignObject> per visualizzare contenuto HTML arbitrario all'interno di un'immagine SVG. Il markup può rappresentare contenuto HTML arbitrario, un delegato RenderFragment o un componente di Razor.

L'esempio seguente mostra:

  • Visualizzazione di un oggetto string (@message).
  • Associazione bidirezionale con un elemento <input> e un campo value.
  • Un componente Robot.
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black" 
        fill="none" />
    <foreignObject x="20" y="20" width="160" height="160">
        <p>@message</p>
    </foreignObject>
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject width="200" height="200">
        <label>
            Two-way binding:
            <input @bind="value" @bind:event="oninput" />
        </label>
    </foreignObject>
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject>
        <Robot />
    </foreignObject>
</svg>

@code {
    private string message = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
        "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

    private string? value;
}

Comportamento di rendering degli spazi vuoti

A meno che la direttiva @preservewhitespace non venga usata con il valore true, lo spazio vuoto aggiuntivo viene rimosso per impostazione predefinita se:

  • Si trova all'inizio o alla fine di un elemento.
  • Si trova all'inizio o alla fine di un parametro RenderFragment/RenderFragment<TValue> (ad esempio, il contenuto figlio passato a un altro componente).
  • Precede o segue un blocco di codice C#, ad esempio @if o @foreach.

La rimozione dello spazio vuoto potrebbe influire sull'output sottoposto a rendering quando si usa una regola CSS, ad esempio white-space: pre. Per disabilitare questa ottimizzazione delle prestazioni e mantenere lo spazio vuoto, eseguire una delle azioni seguenti:

  • Aggiungere la direttiva @preservewhitespace true all'inizio del file Razor (.razor) per applicare la preferenza a un componente specifico.
  • Aggiungere la direttiva @preservewhitespace true all'interno di un file _Imports.razor per applicare la preferenza a una sottodirectory o all'intero progetto.

Nella maggior parte dei casi, non è necessaria alcuna azione perché le app continuano in genere a comportarsi normalmente (ma più velocemente). Se la rimozione di uno spazio vuoto causa un problema di rendering per un determinato componente, usare @preservewhitespace true in tale componente per disabilitare questa ottimizzazione.

Uno spazio vuoto viene conservato nel markup di origine di un componente. Il rendering di un testo con soli spazi vuoti viene eseguito nel DOM del browser anche quando non sono presenti effetti visivi.

Si consideri il markup del componente seguente:

<ul>
    @foreach (var item in Items)
    {
        <li>
            @item.Text
        </li>
    }
</ul>

L'esempio precedente esegue il rendering degli spazi vuoti non necessari seguenti:

  • All'esterno del blocco di codice @foreach.
  • Attorno all'elemento <li>.
  • Attorno all'output @item.Text.

Un elenco di 100 elementi restituisce oltre 400 aree di spazi vuoti. Nessuno degli spazi vuoti aggiuntivi influisce visivamente sull'output sottoposto a rendering.

Quando si esegue il rendering di contenuto HTML statico, gli spazi vuoti all'interno di un tag non vengono mantenuti. Ad esempio, visualizzare l'output sottoposto a rendering del tag <img> seguente in un file Razor del componente (.razor):

<img     alt="Example image"   src="img.png"     />

Gli spazi vuoti non vengono mantenuti dal markup precedente:

<img alt="Example image" src="img.png" />

Componente radice

Un componente radice (componente radiceRazor) è il primo componente caricato di qualsiasi gerarchia di componenti creata dall'app.

In un'app creata dal Blazor modello di progetto app Web, il App componente (App.razor) viene specificato come componente radice predefinito dal parametro di tipo dichiarato per la chiamata a MapRazorComponents<TRootComponent> nel file lato Program server. L'esempio seguente mostra l'uso del App componente come componente radice, ovvero l'impostazione predefinita per un'app creata dal Blazor modello di progetto:

app.MapRazorComponents<App>();

Nota

Rendere interattivo un componente radice, ad esempio il App componente, non è supportato.

In un'app creata dal modello di Blazor Server progetto, il App componente (App.razor) viene specificato come componente radice predefinito in Pages/_Host.cshtml usando l'helper tag del componente:

<component type="typeof(App)" render-mode="ServerPrerendered" />

In un'app creata dal modello di Blazor WebAssembly progetto, il App componente (App.razor) viene specificato come componente radice predefinito nel Program file:

builder.RootComponents.Add<App>("#app");

Nel codice precedente, il selettore CSS, #app, indica che il App componente è specificato per in <div>wwwroot/index.html con un id di app:

<div id="app">...</app>

Le app MVC e Razor Pages possono anche usare l'helpertag del componente per registrare i componenti radice sottoposti Blazor WebAssembly a rendering statico:

<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

I componenti sottoposti a rendering statico possono essere aggiunti solo all'app. Non possono essere rimossi o aggiornati in seguito.

Per ulteriori informazioni, vedi le seguenti risorse: