ASP.NET Core-Razor-Komponenten

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

In diesem Artikel wird erläutert, wie Sie Razor-Komponenten erstellen und in Blazor-Apps verwenden. Sie finden außerdem Anleitungen zur Razor-Syntax, zu Komponentennamen, Namespaces und Komponentenparametern.

Razor-Komponenten

Blazor-Apps werden mit Razor-Komponenten erstellt, die informell als Blazor-Komponenten oder einfach Komponenten bezeichnet werden. Eine Komponente ist ein eigenständiger Teil der Benutzeroberfläche mit Verarbeitungslogik, die dynamisches Verhalten ermöglicht. Komponenten können geschachtelt, wiederverwendet, von Projekten gemeinsam genutzt und in MVC- sowie Razor Pages-Apps verwendet werden.

Die Komponenten werden in einer In-Memory-Darstellung des Dokumentobjektmodells (DOM) des Browsers gerendert, die als Renderstruktur bezeichnet wird. Mit dieser Struktur lässt sich die Benutzeroberfläche flexibel und effizient aktualisieren.

Obwohl "RazorKomponenten" einige Benennungen mit anderen Technologien zur Wiedergabe von ASP.NET Core-Inhalten teilt, müssen Razor Komponenten von den folgenden verschiedenen Features in ASP.NET Core unterschieden werden:

Komponentenklassen

Komponenten werden mithilfe einer Kombination aus C# und HTML-Markup in Razor-Komponentendateien mit der Dateierweiterung .razor implementiert.

Standardmäßig ist ComponentBase die Basisklasse für Komponenten, die durch Razor-Komponentendateien beschrieben werden. ComponentBase implementiert die niedrigste Abstraktion von Komponenten, die Schnittstelle IComponent. ComponentBase definiert Komponenteneigenschaften und -methoden für grundlegende Funktionen, z. B. zum Verarbeiten einer Reihe integrierter Ereignisse des Komponentenlebenszyklus.

ComponentBase in dotnet/aspnetcore Referenzquelle: Die Referenzquelle enthält zusätzliche Hinweise zu den integrierten Lebenszyklusereignissen. Beachten Sie jedoch, dass die internen Implementierungen von Komponentenfeatures jederzeit ohne Ankündigung geändert werden können.

Hinweis

Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus. Weitere Informationen finden Sie unter How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Auswählen eines Versionstags von ASP.NET Core-Quellcode (dotnet/AspNetCore.Docs #26205)).

Entwickler*innen erstellen in der Regel Razor-Komponenten aus Razor-Komponentendateien (.razor) oder bauen ihre Komponenten auf ComponentBase auf, aber Komponenten können auch durch die Implementierung von IComponenterstellt werden. Von Entwickler*innen erzeugte Komponenten, die IComponent implementieren, können das Rendern auf niedriger Ebene steuern, wobei das Rendern mit Ereignissen und Lebenszyklusmethoden, die der Entwickler erstellen und verwalten muss, manuell auszulösen ist.

Razor-Syntax

Für Komponenten wird die Razor-Syntax verwendet. Von Komponenten werden zwei Razor-Features häufig verwendet: Anweisungen und Anweisungsattribute. Dies sind reservierte Schlüsselwörter, die im Razor-Markup mit dem Präfix @ angezeigt werden:

  • Anweisungen: Diese ändern, wie Komponentenmarkup analysiert oder ausgeführt wird. Beispielsweise gibt die @page-Anweisung eine routingfähige Komponente mit einer Routenvorlage an und kann direkt über die Anforderung eines Benutzers im Browser unter einer bestimmten URL erreicht werden.

    Standardmäßig werden die Direktiven einer Komponente am Anfang einer Komponentendefinition (.razor-Datei) in einer konsistenten Reihenfolge platziert. Bei wiederholten Direktiven werden Direktiven alphabetisch nach Namespace oder Typ sortiert, mit Ausnahme von @using-Direktiven, die eine spezielle Reihenfolge auf zweiter Ebene aufweisen.

    Die folgende Reihenfolge wird von Blazor-Beispiel-Apps und Dokumentationen übernommen. Komponenten, die von einer Blazor-Projektvorlage bereitgestellt werden, können sich von der folgenden Reihenfolge unterscheiden und ein anderes Format verwenden. BlazorFramework-Identity-komponenten enthalten z. B. leere Zeilen zwischen @using-Direktivenblöcken und @inject-Direktivenblöcken. Sie können ein benutzerdefiniertes Sortierschema und ein benutzerdefiniertes Format in Ihren eigenen Apps verwenden.

    Dokumentations- und Beispielreihenfolge der App-Direktive Razor:

    • @page
    • @rendermode (.NET 8 oder höher)
    • @using
      • System Namespaces (alphabetische Reihenfolge)
      • Microsoft Namespaces (alphabetische Reihenfolge)
      • API-Namespaces von Dritten (alphabetische Reihenfolge)
      • Anwendungs-Namespaces (alphabetische Reihenfolge)
    • Andere Direktiven (alphabetische Reihenfolge)

    Unter den Direktiven werden keine leeren Zeilen angezeigt. Eine leere Zeile wird zwischen den Direktiven und der ersten Zeile des Razor Markups angezeigt.

    Beispiel:

    @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>
    
    ...
    
  • Anweisungsattribute: Diese ändern, wie ein Komponentenelement analysiert oder ausgeführt wird.

    Beispiel:

    <input @bind="episodeId" />
    

    Sie können Attributwerten von Anweisungen bei nicht expliziten Razor-Ausdrücke (@bind="@episodeId") das @-Symbol als Präfix voranstellen, dies wird jedoch nicht empfohlen und in den Beispielen in der Dokumentation auch nicht beschrieben.

In Komponenten verwendete Anweisungen und Anweisungsattribute werden in diesem Artikel und in anderen Artikeln der Blazor-Dokumentation näher erläutert. Allgemeine Informationen zur Razor-Syntax finden Sie in der Referenz zur Razor-Syntax für ASP.NET Core.

Komponentenname, Klassenname und Namespace

Der Name einer Komponente muss mit einem Großbuchstaben beginnen:

Unterstützt:ProductDetail.razor

Nicht unterstützt:productDetail.razor

Allgemeine Blazor-Namenskonventionen, die in der gesamten Blazor-Dokumentation verwendet werden:

  • Für Dateipfade und Dateinamen wird die Pascal-Schreibweise† verwendet. Sie werden vor den Codebeispielen angezeigt. Wenn ein Pfad vorhanden ist, gibt er den typischen Ordnerspeicherort an. Beispielsweise gibt Components/Pages/ProductDetail.razor an, dass der Dateiname der ProductDetail-Komponente ProductDetail.razor lautet und die Komponente im Ordner Pages des Components-Ordners der App enthalten ist.
  • Die Pfade der Komponentendateien für routingfähige Komponenten entsprechen ihren URLs im Kebab Case‡, wobei die Wörter in der Routenvorlage einer Komponente durch Bindestriche getrennt werden. Beispielsweise wird die Komponente ProductDetail mit der Routenvorlage /product-detail (@page "/product-detail") in einem Browser an der relativen URL /product-detail angefordert.

† Bei der Pascal-Schreibweise (Camel-Case-Schreibweise mit großem Anfangsbuchstaben) werden keine Leerzeichen und Interpunktionszeichen verwendet, und der erste Buchstabe jedes Worts, einschließlich des ersten Worts, ist ein Großbuchstabe.
‡Kebab Case ist eine Benennungskonvention ohne Leerzeichen und Interpunktion, die Kleinbuchstaben und Bindestriche zwischen Wörtern verwendet.

Komponenten sind normale C#-Klassen und können an beliebiger Stelle innerhalb eines Projekts eingefügt werden. Komponenten, die Webseiten erzeugen, befinden sich in der Regel im Ordner Components/Pages. Nicht für Seiten verwendete Komponenten werden häufig im Ordner Components oder einem benutzerdefinierten Ordner gespeichert, der dem Projekt hinzugefügt wurde.

In der Regel wird der Namespace einer Komponente aus dem Stammnamespace der App und dem Speicherort (Ordner) der Komponente in der App abgeleitet. Wenn der Stammnamespace der App BlazorSample lautet und sich die Counter Komponente im Ordner Components/Pages befindet, gilt Folgendes:

  • der Namespace der Counter-Komponente BlazorSample.Components.Pages, und
  • der vollqualifizierten Typname der Komponente ist BlazorSample.Components.Pages.Counter.

Fügen Sie für benutzerdefinierte Ordner, die Komponenten enthalten, der übergeordneten Komponente oder der _Imports.razor-Datei der App eine @using-Anweisung hinzu. Das folgende Beispiel stellt Komponenten im Ordner AdminComponents zur Verfügung:

@using BlazorSample.AdminComponents

Hinweis

@using-Direktiven in der _Imports.razor-Datei werden nur auf Razor-Dateien (.razor), nicht auf C#-Dateien (.cs), angewendet.

using-Anweisungen mit Alias werden unterstützt. Im folgenden Beispiel wird die öffentliche WeatherForecast-Klasse der GridRendering-Komponente in einer Komponente an anderer Stelle in der App als WeatherForecast zur Verfügung gestellt:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

Auf Komponenten kann auch mit ihrem vollqualifizierten Namen verwiesen werden. Hierfür ist keine @using-Anweisung erforderlich. Im folgenden Beispiel wird direkt auf die ProductDetail-Komponente im Ordner AdminComponents/Pages der App verwiesen:

<BlazorSample.AdminComponents.Pages.ProductDetail />

Der Namespace einer mit Razor erstellten Komponente basiert auf Folgendem (nach Priorität):

  • Die @namespace-Anweisung im Markup der Razor-Datei (z. B. @namespace BlazorSample.CustomNamespace).
  • Der RootNamespace des Projekts in der Projektdatei (z. B. <RootNamespace>BlazorSample</RootNamespace>).
  • Der Projektnamespace und der Pfad vom Projektstamm zur Komponente. Das Framework löst beispielsweise für die Home-Komponente den Pfad {PROJECT NAMESPACE}/Components/Pages/Home.razor mit dem Projektnamespace BlazorSample in den Namespace BlazorSample.Components.Pages auf. {PROJECT NAMESPACE} ist der Projektnamespace. Komponenten folgen den Namensbindungsregeln für C#. Für die Home-Komponente in diesem Beispiel werden folgende Komponenten berücksichtigt:
    • Im gleichen Ordner: Components/Pages.
    • Komponenten im Stammverzeichnis des Projekts, die nicht explizit einen anderen Namespace angeben

Folgendes wird nicht unterstützt:

  • Die global::-Qualifizierung.
  • Unvollständig qualifizierte Namen. Beispielsweise können Sie einer Komponente nicht @using BlazorSample.Components hinzufügen und dann mit <Layout.NavMenu></Layout.NavMenu> auf die NavMenu-Komponente im Ordner Components/Layout (Components/Layout/NavMenu.razor) der App verweisen.

Der Name einer Komponente muss mit einem Großbuchstaben beginnen:

Unterstützt:ProductDetail.razor

Nicht unterstützt:productDetail.razor

Allgemeine Blazor-Namenskonventionen, die in der gesamten Blazor-Dokumentation verwendet werden:

  • Für Dateipfade und Dateinamen wird die Pascal-Schreibweise† verwendet. Sie werden vor den Codebeispielen angezeigt. Wenn ein Pfad vorhanden ist, gibt er den typischen Ordnerspeicherort an. Beispielsweise gibt Pages/ProductDetail.razor an, dass der Dateiname der ProductDetail-Komponente ProductDetail.razor lautet und die Komponente im Ordner Pages der App enthalten ist.
  • Die Pfade der Komponentendateien für routingfähige Komponenten entsprechen ihren URLs im Kebab Case‡, wobei die Wörter in der Routenvorlage einer Komponente durch Bindestriche getrennt werden. Beispielsweise wird die Komponente ProductDetail mit der Routenvorlage /product-detail (@page "/product-detail") in einem Browser an der relativen URL /product-detail angefordert.

† Bei der Pascal-Schreibweise (Camel-Case-Schreibweise mit großem Anfangsbuchstaben) werden keine Leerzeichen und Interpunktionszeichen verwendet, und der erste Buchstabe jedes Worts, einschließlich des ersten Worts, ist ein Großbuchstabe.
‡Kebab Case ist eine Benennungskonvention ohne Leerzeichen und Interpunktion, die Kleinbuchstaben und Bindestriche zwischen Wörtern verwendet.

Komponenten sind normale C#-Klassen und können an beliebiger Stelle innerhalb eines Projekts eingefügt werden. Komponenten, die Webseiten erzeugen, befinden sich in der Regel im Ordner Pages. Nicht für Seiten verwendete Komponenten werden häufig im Ordner Shared oder einem benutzerdefinierten Ordner gespeichert, der dem Projekt hinzugefügt wurde.

In der Regel wird der Namespace einer Komponente aus dem Stammnamespace der App und dem Speicherort (Ordner) der Komponente in der App abgeleitet. Wenn der Stammnamespace der App BlazorSample lautet und sich die Counter Komponente im Ordner Pages befindet, gilt Folgendes:

  • der Namespace der Counter-Komponente BlazorSample.Pages, und
  • der vollqualifizierten Typname der Komponente ist BlazorSample.Pages.Counter.

Fügen Sie für benutzerdefinierte Ordner, die Komponenten enthalten, der übergeordneten Komponente oder der _Imports.razor-Datei der App eine @using-Anweisung hinzu. Das folgende Beispiel stellt Komponenten im Ordner AdminComponents zur Verfügung:

@using BlazorSample.AdminComponents

Hinweis

@using-Direktiven in der _Imports.razor-Datei werden nur auf Razor-Dateien (.razor), nicht auf C#-Dateien (.cs), angewendet.

using-Anweisungen mit Alias werden unterstützt. Im folgenden Beispiel wird die öffentliche WeatherForecast-Klasse der GridRendering-Komponente in einer Komponente an anderer Stelle in der App als WeatherForecast zur Verfügung gestellt:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

Auf Komponenten kann auch mit ihrem vollqualifizierten Namen verwiesen werden. Hierfür ist keine @using-Anweisung erforderlich. Im folgenden Beispiel wird direkt auf die ProductDetail-Komponente im Ordner Components der App verwiesen:

<BlazorSample.Components.ProductDetail />

Der Namespace einer mit Razor erstellten Komponente basiert auf Folgendem (nach Priorität):

  • Die @namespace-Anweisung im Markup der Razor-Datei (z. B. @namespace BlazorSample.CustomNamespace).
  • Der RootNamespace des Projekts in der Projektdatei (z. B. <RootNamespace>BlazorSample</RootNamespace>).
  • Der Projektnamespace und der Pfad vom Projektstamm zur Komponente. Das Framework löst beispielsweise für die Index-Komponente den Pfad {PROJECT NAMESPACE}/Pages/Index.razor mit dem Projektnamespace BlazorSample in den Namespace BlazorSample.Pages auf. {PROJECT NAMESPACE} ist der Projektnamespace. Komponenten folgen den Namensbindungsregeln für C#. Für die Index-Komponente in diesem Beispiel werden folgende Komponenten berücksichtigt:
    • Im gleichen Ordner: Pages.
    • Komponenten im Stammverzeichnis des Projekts, die nicht explizit einen anderen Namespace angeben

Folgendes wird nicht unterstützt:

  • Die global::-Qualifizierung.
  • Unvollständig qualifizierte Namen. Beispielsweise können Sie einer Komponente nicht @using BlazorSample hinzufügen und dann mit <Shared.NavMenu></Shared.NavMenu> auf die NavMenu-Komponente im Ordner Shared (Shared/NavMenu.razor) der App verweisen.

Unterstützung für partielle Klassen

Komponenten werden als partielle C#-Klassen generiert und mit einer der folgenden Vorgehensweisen erstellt:

  • Eine einzelne Datei enthält C#-Code, der in einem oder mehreren @code-Blöcken, HTML-Markup und Razor-Markup definiert ist. In Blazor-Projektvorlagen werden Komponenten mithilfe einer einzelnen Datei definiert.
  • HTML- und Razor-Markup werden in einer Razor-Datei (.razor) gespeichert. C#-Code wird in einer CodeBehind-Datei gespeichert, die als partielle Klasse (.cs) definiert ist.

Hinweis

Ein Komponentenstylesheet, das komponentenspezifische Stile definiert, ist eine eigene Datei (.css). Die CSS-Isolation von Blazor wird weiter unten unter CSS-Isolation von Blazor in ASP.NET Core beschrieben.

Das folgende Beispiel zeigt die Counter-Standardkomponente mit einem @code-Block in einer App, die aus einer Blazor-Projektvorlage generiert wurde. Markup und C#-Code befinden sich in derselben Datei. Dies ist der häufigste Ansatz bei der Komponentenerstellung.

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++;
    }
}

In der folgenden Counter-Komponente werden Präsentations-HTML und Razor-Markup aus C#-Code unter Verwendung einer CodeBehind-Datei mit einer partiellen Klasse aufgeteilt. Die Trennung des Markups vom C#-Code wird von einigen Organisationen und Entwickler*innen bevorzugt, um ihren Komponentencode so zu organisieren, dass er ihren Arbeitsgewohnheiten entspricht. So können beispielsweise Benutzeroberflächenxpert*innen der Organisation unabhängig von anderen Entwickler*innen, die an der C#-Logik der Komponente arbeiten, an der Präsentationsebene arbeiten. Der Ansatz ist auch beim Arbeiten mit automatisch generiertem Code oder Quellgeneratoren hilfreich. Weitere Informationen finden Sie unter Partielle Klassen und Methoden (C#-Programmierhandbuch).

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++;
        }
    }
}

@using-Direktiven in der _Imports.razor-Datei werden nur auf Razor-Dateien (.razor), nicht auf C#-Dateien (.cs), angewendet. Fügen Sie einer partiellen Klassendatei ggf. Namespaces hinzu.

Typische Namespaces, die von Komponenten verwendet werden:

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;

Typische Namespaces enthalten auch den Namespace der App und den Namespace, der dem Ordner Components der App entspricht:

using BlazorSample;
using BlazorSample.Components;

Es können auch weitere Ordner eingeschlossen werden, z. B. der Ordner Layout:

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;

Typische Namespaces enthalten auch den Namespace der App und den Namespace, der dem Ordner Shared der App entspricht:

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;

Typische Namespaces enthalten auch den Namespace der App und den Namespace, der dem Ordner Shared der App entspricht:

using BlazorSample;
using BlazorSample.Shared;

Angeben einer Basisklasse

Die @inherits-Anweisung wird verwendet, um eine Basisklasse für eine Komponente anzugeben. Im Gegensatz zur Verwendung von partiellen Klassen, die nur Markup von der C#-Logik trennen, können Sie mit einer Basisklasse C#-Code für die Verwendung in einer Gruppe von Komponenten erben, die die Eigenschaften und Methoden der Basisklasse teilen. Die Verwendung von Basisklassen reduziert die Coderedundanz in Apps und ist nützlich, wenn Basiscode aus Klassenbibliotheken für mehrere Apps bereitgestellt wird. Weitere Informationen finden Sie unter Vererbung in C# und .NET.

Im folgenden Beispiel wird die Basisklasse BlazorRocksBase1 von ComponentBase abgeleitet.

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!";
}

Routing

Das Routing in Blazor erfolgt, indem mit einer @page-Anweisung eine Routenvorlage für jede zugängliche Komponente in der App bereitgestellt wird. Wenn eine Razor-Datei mit einer @page-Anweisung kompiliert wird, wird der generierten Klasse RouteAttribute hinzugefügt und so die Routenvorlage angegeben. Zur Laufzeit sucht der Router nach Komponentenklassen mit einem RouteAttribute und rendert die Komponente, deren Routenvorlage mit der angeforderten URL übereinstimmt.

Die folgende HelloWorld-Komponente verwendet eine Routenvorlage /hello-world, und die gerenderte Webseite für die Komponente ist an der relativen URL /hello-world erreichbar.

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>

Die vorangehende Komponente wird im Browser unter /hello-world geladen, unabhängig davon, ob Sie die Komponente der Benutzeroberflächennavigation der App hinzufügen. Optional können Komponenten zur NavMenu-Komponente hinzugefügt werden, sodass in der Benutzeroberflächennavigation der App ein Link zur Komponente angezeigt wird.

Für die vorherigen HelloWorld-Komponente können Sie eine NavLink-Komponente zur NavMenu-Komponente hinzufügen. Weitere Informationen, einschließlich Beschreibungen der Komponenten NavLink und NavMenu, finden Sie unter Routing und Navigation in Blazor in ASP.NET Core.

Markup

Die Benutzeroberfläche einer Komponente wird mithilfe der Razor-Syntax definiert, die aus Razor-Markup, C# und HTML besteht. Wenn eine App kompiliert wird, werden das HTML-Markup und die C#-Renderinglogik in eine Komponentenklasse konvertiert. Der Name der generierten Klasse entspricht dem Namen der Datei.

Member der Komponentenklasse werden in einem oder mehreren @code-Blöcken definiert. In @code-Blöcken wird der Komponentenzustand angegeben und mit C# verarbeitet:

  • Eigenschaften- und Feldinitialisierer
  • Parameterwerte aus Argumenten, die von übergeordneten Komponenten und Routenparametern übergeben werden
  • Methoden für die Behandlung von Benutzerereignissen, Lebenszyklusereignissen und benutzerdefinierter Komponentenlogik

Komponentenmember werden in der Renderinglogik mithilfe von C#-Ausdrücken verwendet, die mit dem Symbol @ beginnen. Beispielsweise wird ein C#-Feld gerendert, indem @ dem Feldnamen vorangestellt wird. Durch die unten gezeigte Markup-Komponente wird Folgendes ausgewertet und gerendert:

  • headingFontStyle für den CSS-Eigenschaftswert font-style des Überschriftenelements.
  • headingText für den Inhalt des Überschriftenelements.

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!";
}

Hinweis

In den Beispielen in der gesamten Blazor-Dokumentation wird für private Member der private-Zugriffsmodifizierer angegeben. Der Bereich privater Member ist auf die Klasse einer Komponente beschränkt. In C# wird jedoch der private-Zugriffsmodifizierer angenommen, wenn kein Zugriffsmodifizierer vorhanden ist. Daher ist das explizite Markieren von Membern als private im eigenen Code optional. Weitere Informationen zu Zugriffsmodifizierern finden Sie unter Zugriffsmodifizierer (C#-Programmierhandbuch).

Das Blazor-Framework verarbeitet eine Komponente intern als Renderstruktur. Dies ist die Kombination aus dem Dokumentobjektmodell einer Komponente und dem Cascading Style Sheet Object Model (CSSOM). Nachdem die Komponente zum ersten Mal gerendert wurde, wird ihre Renderstruktur als Reaktion auf Ereignisse erneut generiert. Blazor vergleicht die neue Renderstruktur mit der vorherigen und wendet alle Änderungen auf das DOM des Browsers für die Anzeige an. Weitere Informationen finden Sie unter Rendering von Razor-Komponenten in ASP.NET Core.

Laut Razor-Syntax werden für C#-Steuerelementstrukturen, Anweisungen und Anweisungsattribute Kleinbuchstaben verwendet (z. B. @if, @code, @bind). Eigenschaftennamen stehen in Großbuchstaben (z. B. @Body für LayoutComponentBase.Body).

Asynchrone Methoden (async) unterstützen nicht die Rückgabe von void.

Das Blazor-Framework verfolgt keine asynchronen Methoden (async) nach, die void zurückgeben. Folglich werden keine Ausnahmen abgefangen, wenn void zurückgegeben wird. Lassen Sie asynchrone Methoden stets Task zurückgeben.

Geschachtelte Komponenten

Komponenten können andere Komponenten enthalten, sofern Sie sie mithilfe der HTML-Syntax deklarieren. Das Markup für die Verwendung einer Komponente sieht wie ein HTML-Tag aus, wobei der Name des Tags der Typ der Komponente ist.

Betrachten Sie die folgende Heading-Komponente, die von anderen Komponenten verwendet werden kann, um eine Überschrift anzuzeigen.

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";
}

Das folgende Markup in der HeadingExample-Komponente rendert die vorherige Heading-Komponente an der Position, an der das <Heading />-Tag angezeigt wird.

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 />

Wenn eine Komponente ein HTML-Element mit einem großgeschriebenen ersten Buchstaben enthält, der nicht mit einem Komponentennamen in demselben Namespace identisch ist, wird eine Warnung ausgegeben, dass das Element einen unerwarteten Namen aufweist. Durch das Hinzufügen einer @using-Anweisung für den Namespace der Komponente wird die Komponente zur Verfügung gestellt, wodurch die Warnung nicht mehr auftritt. Weitere Informationen finden Sie im Abschnitt Komponentenname, Klassenname und Namespace.

Das in diesem Abschnitt gezeigte Beispiel für die Heading-Komponente weist keine @page-Anweisung auf. Daher können Benutzer nicht über eine direkte Anforderung im Browser auf die Heading-Komponente zugreifen. Jede Komponente mit einer @page-Anweisung kann jedoch in einer anderen Komponente geschachtelt werden. Wenn auf die Heading-Komponente direkt zugegriffen werden kann, indem am Anfang der Razor-Datei @page "/heading" eingeschlossen wird, wird die Komponente für Browseranforderungen sowohl unter /heading als auch unter /heading-example gerendert.

Komponentenparameter

Komponentenparameter übergeben Daten an Komponenten und werden mit öffentlichen C#-Eigenschaften für die Komponentenklasse mit dem [Parameter]-Attribut definiert. Im folgenden Beispiel werden ein integrierter Verweistyp (System.String) und ein benutzerdefinierter Verweistyp (PanelBody) als Komponentenparameter übergeben.

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"
        };
}

Warnung

Die Bereitstellung von Anfangswerten für Komponentenparameter wird unterstützt. Erstellen Sie jedoch keine Komponente, die in die eigenen Parameter schreibt, nachdem die Komponente zum ersten Mal gerendert wurde. Weitere Informationen finden Sie unter Vermeiden des Überschreibens von Parametern in ASP.NET Core Blazor.

Die Komponentenparameter Title und Body der ParameterChild-Komponente werden durch Argumente im HTML-Tag festgelegt, das die Instanz der Komponente rendert. Die folgende ParameterParent-Komponente rendert zwei ParameterChild-Komponenten:

  • Die erste ParameterChild-Komponente wird ohne Angabe von Parameterargumenten gerendert.
  • Die zweite ParameterChild-Komponente empfängt Werte für Title und Body von der ParameterParent-Komponente, die mit einem expliziten C#-Ausdruck die Werte der Eigenschaften von PanelBody festlegt.

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" })" />

Das folgende gerenderte HTML-Markup der ParameterParent-Komponente enthält Standardwerte der ParameterChild-Komponente, wenn die ParameterParent-Komponente keine Komponentenparameterwerte angibt. Wenn die ParameterParent-Komponente Komponentenparameterwerte angibt, ersetzen diese die Standardwerte der ParameterChild-Komponente.

Hinweis

Im folgenden gerenderten HTML-Markup werden aus Gründen der Übersichtlichkeit keine gerenderten CSS-Formatklassen angezeigt.

<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>

Weisen Sie einem Komponentenparameter ein C#-Feld, eine C#-Eigenschaft oder das Ergebnis einer Methode als HTML-Attributwert zu. Der Wert des Attributs kann in der Regel ein beliebiger C#-Ausdruck sein, der dem Typ des Parameters entspricht. Der Wert des Attributs kann optional mit einem Razor-reservierten @-Symbol eingeleitet werden. Dies ist jedoch nicht erforderlich.

Wenn der Komponentenparameter vom Typ „string“ ist, wird der Attributwert stattdessen standardmäßig als C#-Zeichenfolgenliteral behandelt. Wenn Sie stattdessen einen C#-Ausdruck angeben möchten, verwenden Sie das Präfix @.

Die folgende ParameterParent2-Komponente zeigt vier Instanzen der vorangehenden ParameterChild-Komponente an und legt ihre Title-Parameterwerte folgendermaßen fest:

  • Der Wert des title-Felds.
  • Das Ergebnis der GetTitle-C#-Methode.
  • Das aktuelle lokale Datum im langen Format mit ToLongDateString unter Verwendung eines impliziten C#-Ausdrucks.
  • Die Title-Eigenschaft des panelData-Objekts.

Anführungszeichen um die Werte von Parameterattributen sind gemäß der HTML5-Spezifikation in den meisten Fällen optional. Beispielsweise wird Value=this anstelle von Value="this" unterstützt. Wir empfehlen jedoch die Verwendung von Anführungszeichen, da sie leichter zu merken und bei webbasierten Technologien weit verbreitet sind.

In der gesamten Dokumentation gibt für Codebeispiele Folgendes:

  • Es werden immer Anführungszeichen verwendet. Beispiel: Value="this".
  • Verwenden Sie das Präfix @ nicht mit Nichtliteralen, außer dies ist erforderlich. Beispiel: Count="ct", wobei ct eine numerische Variable ist. Count="@ct" ist ein gültiger stilistischer Ansatz, aber die Dokumentation und die Beispiele übernehmen die Konvention nicht.
  • Vermeiden Sie immer @ für Literale außerhalb von Razor-Ausdrücken. Beispiel: IsFixed="true". Dazu gehören auch Schlüsselwörter (z. B. this) und null, aber Sie können sie bei Bedarf verwenden. Zum Beispiel ist IsFixed="@true" ungewöhnlich, wird aber unterstützt.

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";
    }
}

Hinweis

Wenn Sie einem Komponentenparameter ein C#-Member zuweisen, stellen Sie dem HTML-Attribut des Parameters kein @ voran.

Richtig (Title ist ein Zeichenfolgenparameter, Count ist ein numerischer Typparameter):

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

Falsch:

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

Anders als bei Razor-Seiten (.cshtml) kann Blazor keine asynchronen Aufgaben in einem Razor-Ausdruck ausführen, während eine Komponente gerendert wird. Der Grund hierfür ist, dass Blazor für das Rendering interaktiver Benutzeroberflächen konzipiert ist. In einer interaktiven Benutzeroberfläche muss auf dem Bildschirm immer etwas angezeigt werden. Daher ist es nicht sinnvoll, den Renderingfluss zu blockieren. Stattdessen wird die asynchrone Arbeit während eines der asynchronen Lebenszyklusereignisse ausgeführt. Nach jedem asynchronen Lebenszyklusereignis kann die Komponente wieder gerendert werden. Folgende Razor-Syntax wird nicht unterstützt:

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

Der Code im vorangehenden Beispiel generiert einen Compilerfehler, wenn die App erstellt wird:

Der 'await'-Operator kann nur innerhalb einer 'async'-Methode verwendet werden. Markieren Sie ggf. diese Methode mit dem 'async'-Modifizierer, und ändern Sie ihren Rückgabetyp in 'Task'.

Um einen Wert für den Parameter Title im vorangehenden Beispiel asynchron abzurufen, kann die Komponente das Lebenszyklusereignis OnInitializedAsync verwenden. Dies wird im folgenden Beispiel veranschaulicht:

<ParameterChild Title="@title" />

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

Weitere Informationen finden Sie unter Rendering von Razor-Komponenten in ASP.NET Core.

Die Verwendung eines expliziten Razor-Ausdrucks zur Verkettung von Text mit einem Ausdrucksergebnis für die Zuweisung zu einem Parameter wird nicht unterstützt. Im folgenden Beispiel wird versucht, den Text Set by mit dem Eigenschaftswert eines Objekts zu verketten. Obwohl diese Syntax in einer Razor-Seite (.cshtml) unterstützt wird, ist sie nicht für die Zuweisung zum Title-Parameter des untergeordneten Elements in einer Komponente gültig. Folgende Razor-Syntax wird nicht unterstützt:

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

Der Code im vorangehenden Beispiel generiert einen Compilerfehler, wenn die App erstellt wird:

Komponentenattribute unterstützen keine komplexen Inhalte (C# und Markup gemischt).

Um die Zuweisung eines zusammengesetzten Werts zu unterstützen, verwenden Sie eine Methode, ein Feld oder eine Eigenschaft. Im folgenden Beispiel wird die Verkettung von Set by und dem Eigenschaftswert eines Objekts in der C#-Methode GetTitle ausgeführt:

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";
    }
}

Weitere Informationen finden Sie unter Razor-Syntaxreferenz für ASP.NET Core.

Warnung

Die Bereitstellung von Anfangswerten für Komponentenparameter wird unterstützt. Erstellen Sie jedoch keine Komponente, die in die eigenen Parameter schreibt, nachdem die Komponente zum ersten Mal gerendert wurde. Weitere Informationen finden Sie unter Vermeiden des Überschreibens von Parametern in ASP.NET Core Blazor.

Komponentenparameter sollten als Auto-Eigenschaften deklariert werden, d. h., ihre get- oder set-Zugriffsmethode sollte keine benutzerdefinierte Logik enthalten. Beispielsweise ist die folgende StartData-Eigenschaft eine Auto-Eigenschaft:

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

Platzieren Sie die benutzerdefinierte Logik nicht in der get- oder set-Zugriffsmethode, da Komponentenparameter ausschließlich zur Verwendung als Kanal für eine übergeordnete Komponente vorgesehen sind, über den Informationen an eine untergeordnete Komponente fließen. Wenn eine set-Zugriffsmethode einer untergeordneten Komponenteneigenschaft Logik enthält, die das erneute Rendern der übergeordneten Komponente bewirkt, resultiert daraus eine Rendering-Endlosschleife.

So transformieren Sie einen empfangenen Parameterwert:

  • Belassen Sie die Parametereigenschaft als Auto-Eigenschaft, um die bereitgestellten Rohdaten darzustellen.
  • Erstellen Sie eine andere Eigenschaft oder Methode, um die transformierten Daten basierend auf der Parametereigenschaft bereitzustellen.

Überschreiben Sie OnParametersSetAsync, um einen empfangenen Parameter jedes Mal zu transformieren, wenn neue Daten empfangen werden.

Das Schreiben eines Anfangswerts in einen Komponentenparameter wird unterstützt, da anfängliche Wertzuweisungen das automatische Komponentenrendering von Blazor nicht beeinträchtigen. Die folgende Zuweisung der aktuellen lokalen DateTime mit DateTime.Now zu StartData ist eine gültige Syntax in einer Komponente:

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

Weisen Sie nach der anfänglichen Zuweisung von DateTime.Now im Entwicklercode keinen Wert zu StartData zu. Weitere Informationen finden Sie unter Vermeiden des Überschreibens von Parametern in ASP.NET Core Blazor.

Wenden Sie das [EditorRequired]-Attribut an, um einen erforderlichen Komponentenparameter anzugeben. Wenn kein Parameterwert angegeben wird, zeigen Editoren oder Buildtools dem Benutzer u. U. Warnungen an. Dieses Attribut ist nur für Eigenschaften gültig, die ebenfalls mit dem [Parameter]-Attribut markiert sind. EditorRequiredAttribute wird zur Entwurfszeit und beim Erstellen der App erzwungen. Das Attribut wird zur Laufzeit nicht erzwungen und garantiert keinen Nicht-null-Parameterwert.

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

Einzeilige Attributlisten werden ebenfalls unterstützt:

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

Verwenden Sie den required-Modifizierer oder die init-Zugriffsmethode nicht bei Eigenschaften von Komponentenparametern. Komponenten werden in der Regel anhand der Reflexion instanziiert und mit Parameterwerten belegt, wodurch die Garantien umgangen werden, die init und required bieten. Verwenden Sie stattdessen das Attribut [EditorRequired], um einen erforderlichen Komponentenparameter anzugeben.

Verwenden Sie die init-Zugriffsmethode nicht für Eigenschaften von Komponentenparameter, da das Festlegen von Werten für Komponentenparameter mit ParameterView.SetParameterPropertiesReflexion verwendet, wodurch die Einschränkung des init-only-Setters umgangen wird. Wenden Sie das [EditorRequired]-Attribut an, um einen erforderlichen Komponentenparameter anzugeben.

Verwenden Sie die init-Zugriffsmethode nicht für Eigenschaften von Komponentenparameter, da das Festlegen von Werten für Komponentenparameter mit ParameterView.SetParameterPropertiesReflexion verwendet, wodurch die Einschränkung des init-only-Setters umgangen wird.

Tuples (API-Dokumentation) werden für Komponentenparameter und RenderFragment-Typen unterstützt. Im folgenden Komponentenparameterbeispiel werden drei Werte in einem Tuple übergeben:

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);
}

Benannte Tupel werden unterstützt, wie im folgenden Beispiel dargestellt:

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)

Tuples (API-Dokumentation) werden für Komponentenparameter und RenderFragment-Typen unterstützt. Im folgenden Komponentenparameterbeispiel werden drei Werte in einem Tuple übergeben:

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);
}

Benannte Tupel werden unterstützt, wie im folgenden Beispiel dargestellt:

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)

Routenparameter

Komponenten können in der Routenvorlage der @page-Anweisung Routenparameter angeben. Der Blazor-Router verwendet Routenparameter, um entsprechende Komponentenparameter aufzufüllen.

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; }
}

Weitere Informationen finden Sie im Abschnitt Routenparameter von ASP.NET Core: Blazor Routing und Navigation. Optionale Routenparameter werden auch unterstützt und im selben Abschnitt behandelt. Informationen zu Catch-All-Routenparametern ({*pageRoute}), die Pfade über mehrere Ordnergrenzen hinweg erfassen, finden Sie im Abschnitt Catch-All-Routenparameter von ASP.NET Core: Blazor Routing und Navigation.

Weitere Informationen finden Sie im Abschnitt Routenparameter von ASP.NET Core: Blazor Routing und Navigation. Optionale Routenparameter werden nicht unterstützt, daher sind zwei @page-Direktiven erforderlich (weitere Informationen finden Sie im Abschnitt Routenparameter). Informationen zu Catch-All-Routenparametern ({*pageRoute}), die Pfade über mehrere Ordnergrenzen hinweg erfassen, finden Sie im Abschnitt Catch-All-Routenparameter von ASP.NET Core: Blazor Routing und Navigation.

Warnung

Mit standardmäßiger aktivierter Komprimierung vermeiden Sie die Erstellung sicherer (authentifizierter/autorisierter) serverseitiger Komponenten, die Daten aus nicht vertrauenswürdigen Quellen rendern. Nicht vertrauenswürdige Quellen umfassen Routenparameter, Abfragezeichenfolgen, Daten aus JS-Interoperabilität und andere Datenquellen, die ein Drittbenutzer steuern kann (Datenbanken, externe Dienste). Weitere Informationen finden Sie unter ASP.NET Core BlazorSignalR Anleitungen und Anleitung zur Risikominderung für ASP.NET Core Blazor interaktives serverseitiges Rendering.

Untergeordnete Inhaltsrenderfragmente

Komponenten können den Inhalt anderer Komponenten festlegen. Die zuweisende Komponente stellt den Inhalt zwischen dem öffnenden und schließenden Tag der untergeordneten Komponente bereit.

Im folgenden Beispiel enthält die RenderFragmentChild-Komponente einen Parameter der ChildContent-Komponenten, der ein als RenderFragment zu renderndes Segment der Benutzeroberfläche darstellt. In der endgültigen HTML-Ausgabe wird der Inhalt an der Position von ChildContent im Razor-Markup der Komponente gerendert.

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; }
}

Wichtig

Die Eigenschaft, die den Inhalt von RenderFragment empfängt, muss gemäß der Konvention ChildContent benannt werden.

Ereignisrückrufe werden für RenderFragment nicht unterstützt.

Die folgende Komponente stellt Inhalt für das Rendern des RenderFragmentChild durch Einfügen des Inhalts zwischen dem öffnenden und schließenden Tag der untergeordneten Komponente bereit.

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>

Aufgrund der Art und Weise, in der Blazor untergeordneten Inhalt rendert, erfordert das Rendern von Komponenten in einer for-Schleife eine lokale Indexvariable, wenn die inkrementierte Schleifenvariable im Inhalt der RenderFragmentChild-Komponente verwendet wird. Das folgende Beispiel kann der vorherigen übergeordneten Komponente hinzugefügt werden:

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

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

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

Alternativ können Sie anstelle einer for-Schleife eine foreach-Schleife mit Enumerable.Range verwenden. Das folgende Beispiel kann der vorherigen übergeordneten Komponente hinzugefügt werden:

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

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

Renderfragmente werden dazu verwendet, untergeordnete Inhalte in allen Blazor Apps zu rendern und werden in den folgenden Artikeln und Artikelabschnitten mit Beispielen beschrieben:

Hinweis

Die in das Blazor Framework integrierten Razor Komponenten verwenden die selbe ChildContent Komponentenparameterkonvention, um ihren Inhalt festzulegen. Sie können die Komponenten sehen, die untergeordnete Inhalte festlegen, indem Sie in der API Dokumentation nach dem Komponenten-Parametereigenschaftsnamen ChildContent suchen (filtert API mit dem Suchbegriff "ChildContent").

Rendern von Fragmenten für wiederverwendbare Renderinglogik

Sie können untergeordnete Komponenten ausschließlich als Möglichkeit zum Wiederverwenden von Renderinglogik ausklammern. Definieren Sie in jedem @code Block der Komponente ein RenderFragment und rendern Sie das Fragment von einem beliebigen Ort aus so oft wie nötig:

@RenderWelcomeInfo

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

@RenderWelcomeInfo

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

Weitere Informationen finden Sie unter Wiederverwenden von Renderinglogik.

Erfassen von Verweisen auf Komponenten

Komponentenverweise bieten eine Möglichkeit, auf eine Komponenteninstanz zum Ausgeben von Befehlen zu verweisen. So erfassen Sie einen Komponentenverweis:

  • Fügen Sie der untergeordneten Komponente ein @ref-Attribut hinzu.
  • Definieren Sie ein Feld mit demselben Typ wie die untergeordnete Komponente.

Wenn die Komponente gerendert wird, wird das Feld mit der Komponenteninstanz aufgefüllt. Anschließend können Sie .NET-Methoden für die Instanz aufrufen.

Betrachten Sie die folgende ReferenceChild-Komponente, die eine Meldung protokolliert, wenn die ChildMethod aufgerufen wird.

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);
    }
}

Ein Komponentenverweis wird erst aufgefüllt, nachdem die Komponente gerendert wurde und die Ausgabe das Element von ReferenceChild enthält. Vor dem Rendern der Komponente gibt es nichts, auf das verwiesen werden kann. Versuchen Sie nicht, eine referenzierte Komponentenmethode direkt an einen Ereignishandler (z. B. @onclick="childComponent!.ChildMethod(5)") aufzurufen, da die Referenzvariable zum Zeitpunkt der Zuweisung des Klick-Ereignisses möglicherweise nicht zugewiesen wird.

Sie können Komponentenverweise bearbeiten, nachdem die Komponente das Rendering abgeschlossen hat, indem Sie die OnAfterRender- oder die OnAfterRenderAsync-Methode verwenden.

Im folgenden Beispiel verwendet die vorangehende ReferenceChild-Komponente.

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);
    }
}

Beim Erfassen von Komponentenverweisen wird zwar eine ähnliche Syntax verwendet, um Elementverweise zu erfassen, das Erfassen von Komponentenverweisen ist jedoch kein JavaScript-Interop-Feature. Komponentenverweise werden nicht an JavaScript-Code übermittelt. Komponentenverweise werden nur in .NET-Code verwendet.

Wichtig

Verwenden Sie keine Komponentenverweise verwenden, um den Zustand von untergeordneten Komponenten zu verändern. Verwenden Sie stattdessen normale deklarative Komponentenparameter, um Daten an untergeordnete Komponenten zu übergeben. Die Verwendung von Komponentenparametern bewirkt, dass untergeordnete Komponenten automatisch zu den richtigen Zeitpunkten erneut gerendert werden. Weitere Informationen finden Sie im Abschnitt Komponentenparameter und im Artikel Datenbindung in Blazor in ASP.NET Core.

Hinzufügen eines Attributs

Attribute können Komponenten mit der @attribute-Anweisung hinzugefügt werden. Im folgenden Beispiel wird das [Authorize]-Attribut auf die Klasse der Komponente angewendet:

@page "/"
@attribute [Authorize]

Attribute für bedingte HTML-Elemente

HTML-Elementattributeigenschaften werden basierend auf dem .NET-Wert bedingt festgelegt. Wenn der Wert false oder null ist, wird die Eigenschaft nicht festgelegt. Wenn der Wert true ist, wird die Eigenschaft festgelegt.

Im folgenden Beispiel bestimmt IsCompleted, ob die checked-Eigenschaft des <input>-Elements festgelegt wird.

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; }
}

Weitere Informationen finden Sie unter Razor-Syntaxreferenz für ASP.NET Core.

Warnung

Einige HTML-Attribute wie aria-pressed funktionieren nicht ordnungsgemäß, wenn der .NET-Typ bool ist. Verwenden Sie in diesen Fällen statt bool einen string-Typ.

Unformatierter HTML-Code

Zeichenfolgen werden normalerweise mithilfe von DOM-Textknoten gerendert. Das bedeutet, dass das darin enthaltene Markup vollständig ignoriert und als Literaltext behandelt wird. Sie können unformatierten HTML-Code rendern, indem Sie den HTML-Inhalt mit einem MarkupString-Wert umschließen. Der Wert wird als HTML oder SVG analysiert und in das DOM eingefügt.

Warnung

Das Rendern von unformatiertem HTML-Code, der aus einer nicht vertrauenswürdigen Quelle stammt, gilt als Sicherheitsrisiko und sollte immer vermieden werden.

Im folgenden Beispiel wird veranschaulicht, wie der MarkupString-Typ verwendet wird, um der gerenderten Ausgabe einer Komponente einen Block mit statischem HTML-Inhalt hinzuzufügen.

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>";
}

Razor-Vorlagen

Renderfragmente können mithilfe der Razor-Vorlagensyntax definiert werden, um einen Benutzeroberflächen-Codeausschnitt zu definieren. Für Razor-Vorlagen wird das folgende Format verwendet:

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

Im folgenden Beispiel wird veranschaulicht, wie Sie RenderFragment- und RenderFragment<TValue>-Werte angeben und Vorlagen direkt in einer-Komponente rendern können. Renderingfragmente können auch als Argumente an Komponentenvorlagen übergeben werden.

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; }
    }
}

Gerenderte Ausgabe des vorangehenden Codes:

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

Statische Ressourcen

In Blazor gilt für statische Ressourcen die Konvention von ASP.NET Core-Apps. Statische Ressourcen befinden sich in einem oder mehreren web root-Ordnern (wwwroot) des Projekts unter dem Ordner wwwroot.

Verwenden Sie einen zur Basis relativen Pfad (/), um auf den Webstamm einer statischen Ressource zu verweisen. Im folgenden Beispiel befindet sich logo.png physisch im Ordner {PROJECT ROOT}/wwwroot/images. {PROJECT ROOT} ist der Projektstamm der App.

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

Komponenten unterstützen keine Notation mit Tilde und Schrägstrich (~/).

Informationen zum Festlegen des Basispfads einer App finden Sie unter Hosten und Bereitstellen von Blazor in ASP.NET Core .

Keine Unterstützung von Taghilfsprogrammen in Komponenten

Tag Helpers werden in Komponenten nicht unterstützt. Sie können Taghilfsobjekte in Blazor bereitstellen, indem Sie eine Komponente mit der gleichen Funktionalität wie das Taghilfsprogramm erstellen und diese stattdessen verwenden.

SVG-Bilder

Da Blazor HTML rendert, werden browsergestützte Bilder wie skalierbare Vektorgrafiken (Scalable Vector Graphics, SVG-Grafiken.svg) über das <img>-Tag unterstützt:

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

Ebenso werden SVG-Bilder in den CSS-Regeln einer Stylesheetdatei (.css) unterstützt:

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

Blazor unterstützt das <foreignObject>-Element, um beliebigen HTML-Code in einer SVG anzuzeigen. Das Markup kann beliebige HTML-, RenderFragment- oder Razor-Komponenten darstellen.

Dies wird im folgenden Beispiel veranschaulicht:

  • Darstellung eines string (@message)
  • Bidirektionale Bindung mit einem <input>-Element und einem value-Feld
  • Eine Robot-Komponente
<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;
}

Verhalten beim Rendern von Leerzeichen

Wenn die @preservewhitespace-Direktive mit dem Wert trueverwendet wird, werden standardmäßig zusätzliche Leerzeichen entfernt, wenn Folgendes gilt:

  • Sie stehen in einem Element am Anfang oder am Ende.
  • Se stehen in einem RenderFragment/RenderFragment<TValue>-Parameter (z. B. untergeordneter Inhalt, der an eine andere Komponente übergeben wird) am Anfang oder am Ende.
  • Sie stehen am Anfang oder Ende eines C#-Codeblocks wie @if oder @foreach.

Das Entfernen der Leerzeichen kann sich auf die gerenderte Ausgabe auswirken, wenn eine CSS-Regel wie white-space: pre verwendet wird. Führen Sie eine der folgenden Aktionen durch, um diese Leistungsoptimierung zu deaktivieren und die Leerzeichen beizubehalten:

  • Fügen Sie oben in der Razor-Datei (.razor) die Anweisung @preservewhitespace true hinzu, um sie auf eine bestimmte Komponente anzuwenden.
  • Fügen Sie die Anweisung @preservewhitespace true in einer _Imports.razor-Datei hinzu, um sie auf ein Unterverzeichnis oder auf das gesamte Projekt anzuwenden.

In den meisten Fällen ist keine Aktion erforderlich, weil sich Apps normalerweise wie gewohnt (aber schneller) verhalten. Falls das Entfernen der Leerzeichen für eine bestimmte Komponente zu Renderingproblemen führt, sollten Sie darin @preservewhitespace true nutzen, um diese Optimierung zu deaktivieren.

Leerzeichen werden im Quellmarkup einer Komponente beibehalten. Text nur mit Leerzeichen wird im DOM des Browsers auch dann gerendert, wenn dies keine visuellen Auswirkungen hat.

Betrachten Sie das folgende Komponentenmarkup:

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

Im vorangehenden Beispiel werden folgende unnötige Leerzeichen gerendert:

  • Außerhalb des Codeblocks @foreach.
  • Im Bereich des Elements <li>.
  • Im Bereich der Ausgabe @item.Text.

Eine Liste von 100 Elementen führt zu mehr als 400 Leerzeichen. Keines der zusätzlichen Leerzeichen wirkt sich visuell auf die gerenderte Ausgabe aus.

Beim Rendern von statischem HTML-Code für Komponenten werden Leerzeichen innerhalb eines Tags nicht beibehalten. Zeigen Sie beispielsweise die gerenderte Ausgabe des folgenden <img>-Tags in einer Razor-Komponentendatei (.razor) an:

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

Leerzeichen aus dem vorangehenden Markup werden nicht beibehalten:

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

Stammkomponente

Eine Razor-Stammkomponente (Stammkomponente) ist die erste geladene Komponente einer von der App erstellten Komponentenhierarchie.

In einer App, die aus der Blazor Web-App-Projektvorlage erstellt wurde, wird die App-Komponente (App.razor) als Standardstammkomponente durch den Typparameter angegeben, der für den Aufruf von MapRazorComponents<TRootComponent> in der serverseitigen Program-Datei deklariert ist. Das folgende Beispiel zeigt die Verwendung der App-Komponente als Stammkomponente, die Standard für eine App ist, die aus der Blazor-Projektvorlage erstellt wurde:

app.MapRazorComponents<App>();

Hinweis

Die Interaktivität einer Stammkomponente, wie z.B. der App-Komponente, wird nicht unterstützt.

In einer App, die aus der Blazor Server-Projektvorlage erstellt wurde, wird die App-Komponente (App.razor) als Standardstammkomponente in Pages/_Host.cshtml mithilfe des Taghilfsprogramms für Komponenten angegeben:

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

In einer App, die aus der Blazor WebAssembly-Projektvorlage erstellt wurde, wird die App-Komponente (App.razor) als Standardstammkomponente in der Program-Datei angegeben:

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

Im vorherigen Code gibt der CSS-Selektor #app an, dass die App-Komponente für <div> in wwwroot/index.html anhand einer id mit dem Wert app angegeben wird:

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

MVC- und Razor Pages-Apps können auch das Taghilfsprogramm für Komponenten verwenden, um statisch gerenderte Blazor WebAssembly-Stammkomponenten zu registrieren:

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

Statisch gerenderte Komponenten können nur der App hinzugefügt werden. Sie können danach nicht entfernt oder aktualisiert werden.

Weitere Informationen finden Sie in den folgenden Ressourcen: