ASP.NET Core Razor コンポーネント

メモ

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の ASP.NET Core 8.0 バージョンをご参照ください。

この記事では、Razor 構文、コンポーネントの名前付け、名前空間、コンポーネント パラメーターに関するガイダンスなど、Blazor アプリで Razor コンポーネントを作成して使用する方法について説明します。

この記事では、アプリ コードが実行される場所を区別するために、サーバー/サーバー側クライアント/クライアント側という用語が使用されます。

  • サーバー/サーバー側: Blazor Web アプリの対話型サーバー側レンダリング (対話型 SSR)。
  • クライアント/クライアント側
    • Blazor Web アプリのクライアント側レンダリング (CSR)。
    • Blazor WebAssembly アプリ。

ドキュメント コンポーネントの例では、通常、対話型レンダリング モードの構成は、コンポーネントの定義ファイル (.razor) 内の @rendermode ディレクティブを使用しては行いません。

  • Blazor Web アプリにおいて、コンポーネントには、コンポーネントの定義ファイル内で、または親コンポーネントから継承された対話型レンダリング モードが適用されている必要があります。 詳細については、「ASP.NET Core Blazor レンダリング モード」を参照してください。

  • スタンドアロン Blazor WebAssembly アプリでは、コンポーネントは示されているように機能し、Blazor WebAssembly アプリ内の WebAssembly 上で常に対話形式で実行されるため、レンダリング モードは必要ありません。

対話型 WebAssembly モードまたは対話型自動レンダリング モードを使用すると、クライアントに送信されたコンポーネント コードを逆コンパイルして検査できます。 プライベート コード、アプリ シークレット、またはその他の機密情報をクライアント側でレンダリングされるコンポーネントに置かないでください。

  • サーバー/サーバー側
    • ホスト型 Blazor WebAssembly アプリの Server プロジェクト。
    • Blazor Server アプリ。
  • クライアント/クライアント側
    • ホスト型 Blazor WebAssembly アプリの Client プロジェクト。
    • Blazor WebAssembly アプリ。

ファイルとフォルダーの目的と場所に関するガイダンスについては、「ASP.NET Core Blazor プロジェクトの構造」をご参照ください。参照先では、Blazor 開始スクリプトの場所と、<head><body> コンテンツの場所についても説明されています。

デモ コードを実行する最善の方法は、ターゲットの .NET のバージョンと一致する Blazor サンプル GitHub リポジトリから、BlazorSample_{PROJECT TYPE} のサンプル アプリをダウンロードすることです。 現時点では、すべてのドキュメント例が同じサンプル アプリに含まれているわけではありませんが、現在 .NET 8 の記事の例のほとんどを .NET 8 サンプル アプリへと移行する作業が行われています。 この作業は、2024 年の第 1 四半期に完了する予定です。

Razor のコンポーネント

Blazor アプリは、Razor コンポーネント (非公式には "Blazor コンポーネント" と呼ばれます) またはコンポーネントのみを使って構築されます。 コンポーネントは、動的な動作を有効にするための処理ロジックを使用するユーザー インターフェイス (UI) の自己完結型の部分です。 コンポーネントは、入れ子、再利用、プロジェクト間での共有を行えることに加え、MVC と Razor ページ アプリで使うことができます。

コンポーネントはレンダリングされると、"レンダリング ツリー" と呼ばれる、ブラウザーのドキュメント オブジェクト モデル (DOM) のメモリ内表現になります。これは、柔軟かつ効率的な方法で UI を更新するために使われます。

コンポーネント クラス

コンポーネントは、.razor ファイル拡張子の Razor コンポーネント ファイルで C# と HTML マークアップの組み合わせを使用して実装されます。

既定では、ComponentBase は Razor コンポーネント ファイルによって記述されるコンポーネントの基底クラスです。 ComponentBase では、コンポーネントの最も低い抽象化である IComponent インターフェイスが実装されます。 ComponentBase は、一連の組み込みコンポーネント ライフサイクル イベントを処理するなどの基本的な機能のコンポーネント プロパティとメソッドを定義します。

dotnet/aspnetcore 参照ソースの ComponentBase: 参照ソースには、組み込みのライフサイクル イベントに関する追加の注釈が含まれています。 ただし、コンポーネント機能の内部実装は、予告なしにいつでも変更される可能性があることに注意してください。

メモ

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

通常、開発者は Razor コンポーネント ファイル (.razor) から Razor コンポーネントを作成するか、ComponentBase のコンポーネントのベースとしてコンポーネントを作成しますが、コンポーネントは IComponent を実装することで構築することもできます。 IComponent を実装する開発者が構築したコンポーネントでは、開発者が作成して維持する必要があるイベントとライフサイクル メソッドを使用してレンダリングを手動でトリガーする必要がある場合に、レンダリングを低レベルで制御できます。

Razor の構文

コンポーネントでは Razor 構文を使用します。 コンポーネント、''ディレクティブ'' および ''ディレクティブ属性'' では、2 つの Razor 機能が広く使用されています。 これらは、Razor マークアップに表示される @ というプレフィックスが付いた予約キーワードです。

  • ディレクティブ: コンポーネント マークアップの解析方法または関数を変更します。 たとえば、@page ディレクティブでは、ルート テンプレートでルーティング可能なコンポーネントを指定します。このディレクティブには、ブラウザーの特定の URL でのユーザーの要求により直接到達できます。

    慣例により、コンポーネント定義 (.razor ファイル) の先頭にあるコンポーネントのディレクティブは、一貫した順序で配置されます。 ディレクティブが繰り返される場合、各ディレクティブは名前空間または種類によってアルファベット順に配置されます。ただし、特別な第 2 レベルの順序を持つ @using ディレクティブは除きます。

    Blazor のサンプル アプリとドキュメントでは、以下の順序が採用されています。 Blazor プロジェクト テンプレートによって提供されるコンポーネントは、以下の順序とは異なり、別の形式を使用している場合があります。 たとえば、Blazor フレームワークの Identity コンポーネントでは、@using ディレクティブのブロックと @inject ディレクティブのブロックの間に空白行が含まれています。 独自のアプリでは、カスタムの順序付けスキームと形式を自由に使用できます。

    ドキュメントとサンプル アプリの Razor ディレクティブの順序:

    • @page
    • @rendermode (.NET 8 以降)
    • @using
      • System 名前空間 (アルファベット順)
      • Microsoft 名前空間 (アルファベット順)
      • サードパーティの API 名前空間 (アルファベット順)
      • アプリの名前空間 (アルファベット順)
    • その他のディレクティブ (アルファベット順)

    各ディレクティブの間に空白行は挿入されません。 ディレクティブと Razor マークアップの 1 行目の間には、空白行が 1 行表示されます。

    例:

    @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>
    
    ...
    
  • ディレクティブ属性: コンポーネント要素の解析方法または関数を変更します。

    例:

    <input @bind="episodeId" />
    

コンポーネントで使用されるディレクティブとディレクティブ属性については、この記事および Blazor ドキュメント セットの他の記事で詳しく説明されています。 Razor の構文の一般的な情報については、「ASP.NET Coreの Razor 構文リファレンス」をご覧ください。

コンポーネント名、クラス名、および名前空間

コンポーネントの名前は大文字で始める必要があります。

サポートされています:ProductDetail.razor

サポートされていません:productDetail.razor

Blazor ドキュメント全体で使用される共通の Blazor の名前付け規則は次のとおりです。

  • ファイル パスとファイル名はパスカル ケース†を使用し、コード例を示す前に表示されます。 パスが存在する場合は、一般的なフォルダーの場所を示します。 たとえば、Components/Pages/ProductDetail.razor は、ProductDetail コンポーネントのファイル名が ProductDetail.razor で、そのコンポーネントがアプリの Components フォルダーの Pages フォルダーに存在することを示します。
  • ルーティング可能なコンポーネントのコンポーネント ファイル パスは、コンポーネントのルート テンプレート内の単語間のスペースに表示されるハイフン付きのケバブ ケース‡ の URL に一致します。 たとえば、ルート テンプレートが /product-detail (@page "/product-detail") の ProductDetail コンポーネントは、ブラウザーの相対 URL /product-detail で要求されます。

† パスカル ケース (大文字のキャメル ケース) は、スペースと句読点を使用せず、大文字の各単語の最初の文字 (最初の単語を含む) を使用する名前付け規則です。
ケバブ ケースは、単語間の小文字とダッシュを使用するスペースと句読点のない名前付け規則です。

コンポーネントは通常の C# クラスであり、プロジェクト内の任意の場所に配置できます。 Web ページを生成するコンポーネントは、通常、Components/Pages フォルダーに存在します。 ページ以外のコンポーネントは、多くの場合、Components フォルダー、またはプロジェクトに追加されたカスタム フォルダーに配置されます。

一般に、コンポーネントの名前空間は、アプリのルート名前空間と、アプリ内のコンポーネントの場所 (フォルダー) から派生します。 アプリのルート名前空間が BlazorSample で、Counter コンポーネントが Components/Pages フォルダーに存在する場合:

  • Counter コンポーネントの名前空間は BlazorSample.Components.Pages になります。
  • コンポーネントの完全修飾型名は BlazorSample.Components.Pages.Counter になります。

コンポーネントを保持するカスタム フォルダーの場合は、@using ディレクティブを親コンポーネントまたはアプリの _Imports.razor ファイルに追加します。 次の例では、AdminComponents フォルダー内のコンポーネントを使用できるようにします。

@using BlazorSample.AdminComponents

メモ

_Imports.razor ファイルの @using ディレクティブは、C# ファイル (.cs) ではなく Razor ファイル (.razor) にのみ適用されます。

エイリアス化された using ステートメントがサポートされています。 次の例では、GridRendering コンポーネントのパブリック WeatherForecast クラスは、アプリ内の他の場所の WeatherForecast コンポーネントと同様に使用できます:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

コンポーネントは、完全修飾名を使用して参照することもできます。この場合、@using ディレクティブは必要ありません。 次の例では、アプリの AdminComponents/Pages フォルダーで ProductDetail コンポーネントを直接参照します。

<BlazorSample.AdminComponents.Pages.ProductDetail />

Razor で作成されるコンポーネントの名前空間は、(優先順に並んだ) 以下に基づきます。

  • Razor ファイルのマークアップ内の @namespace ディレクティブ (@namespace BlazorSample.CustomNamespace など)。
  • プロジェクト ファイル内のプロジェクトの RootNamespace (<RootNamespace>BlazorSample</RootNamespace> など)。
  • プロジェクトの名前空間と、プロジェクト ルートからコンポーネントへのパス。 たとえば、フレームワークでは、BlazorSample のプロジェクト名前空間で {PROJECT NAMESPACE}/Components/Pages/Home.razorHome コンポーネントの名前空間 BlazorSample.Components.Pages に解決されます。 {PROJECT NAMESPACE} はプロジェクトの名前空間です。 コンポーネントは C# の名前のバインド規則に従います。 この例の Home コンポーネントの場合、スコープ内のコンポーネントは、次のすべてのコンポーネントです。
    • 同じフォルダー (Components/Pages) に含まれるもの。
    • 別の名前空間を明示的に指定しない、プロジェクトのルート内のコンポーネント。

以下はサポートされていません

  • global:: 修飾。
  • 部分修飾名。 たとえば、@using BlazorSample.Components をコンポーネントに追加してから、アプリの Components/Layout フォルダー (Components/Layout/NavMenu.razor) の NavMenuコンポーネントを <Layout.NavMenu></Layout.NavMenu> で参照することはできません。

コンポーネントの名前は大文字で始める必要があります。

サポートされています:ProductDetail.razor

サポートされていません:productDetail.razor

Blazor ドキュメント全体で使用される共通の Blazor の名前付け規則は次のとおりです。

  • ファイル パスとファイル名はパスカル ケース†を使用し、コード例を示す前に表示されます。 パスが存在する場合は、一般的なフォルダーの場所を示します。 たとえば、Pages/ProductDetail.razor は、ProductDetail コンポーネントのファイル名が ProductDetail.razor で、そのコンポーネントがアプリの Pages フォルダーに存在することを示します。
  • ルーティング可能なコンポーネントのコンポーネント ファイル パスは、コンポーネントのルート テンプレート内の単語間のスペースに表示されるハイフン付きのケバブ ケース‡ の URL に一致します。 たとえば、ルート テンプレートが /product-detail (@page "/product-detail") の ProductDetail コンポーネントは、ブラウザーの相対 URL /product-detail で要求されます。

† パスカル ケース (大文字のキャメル ケース) は、スペースと句読点を使用せず、大文字の各単語の最初の文字 (最初の単語を含む) を使用する名前付け規則です。
ケバブ ケースは、単語間の小文字とダッシュを使用するスペースと句読点のない名前付け規則です。

コンポーネントは通常の C# クラスであり、プロジェクト内の任意の場所に配置できます。 Web ページを生成するコンポーネントは、通常、Pages フォルダーに存在します。 ページ以外のコンポーネントは、多くの場合、Shared フォルダー、またはプロジェクトに追加されたカスタム フォルダーに配置されます。

一般に、コンポーネントの名前空間は、アプリのルート名前空間と、アプリ内のコンポーネントの場所 (フォルダー) から派生します。 アプリのルート名前空間が BlazorSample で、Counter コンポーネントが Pages フォルダーに存在する場合:

  • Counter コンポーネントの名前空間は BlazorSample.Pages になります。
  • コンポーネントの完全修飾型名は BlazorSample.Pages.Counter になります。

コンポーネントを保持するカスタム フォルダーの場合は、@using ディレクティブを親コンポーネントまたはアプリの _Imports.razor ファイルに追加します。 次の例では、AdminComponents フォルダー内のコンポーネントを使用できるようにします。

@using BlazorSample.AdminComponents

メモ

_Imports.razor ファイルの @using ディレクティブは、C# ファイル (.cs) ではなく Razor ファイル (.razor) にのみ適用されます。

エイリアス化された using ステートメントがサポートされています。 次の例では、GridRendering コンポーネントのパブリック WeatherForecast クラスは、アプリ内の他の場所の WeatherForecast コンポーネントと同様に使用できます:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

コンポーネントは、完全修飾名を使用して参照することもできます。この場合、@using ディレクティブは必要ありません。 次の例では、アプリの Components フォルダーで ProductDetail コンポーネントを直接参照します。

<BlazorSample.Components.ProductDetail />

Razor で作成されるコンポーネントの名前空間は、(優先順に並んだ) 以下に基づきます。

  • Razor ファイルのマークアップ内の @namespace ディレクティブ (@namespace BlazorSample.CustomNamespace など)。
  • プロジェクト ファイル内のプロジェクトの RootNamespace (<RootNamespace>BlazorSample</RootNamespace> など)。
  • プロジェクトの名前空間と、プロジェクト ルートからコンポーネントへのパス。 たとえば、フレームワークでは、BlazorSample のプロジェクト名前空間で {PROJECT NAMESPACE}/Pages/Index.razorIndex コンポーネントの名前空間 BlazorSample.Pages に解決されます。 {PROJECT NAMESPACE} はプロジェクトの名前空間です。 コンポーネントは C# の名前のバインド規則に従います。 この例の Index コンポーネントの場合、スコープ内のコンポーネントは、次のすべてのコンポーネントです。
    • 同じフォルダー (Pages) に含まれるもの。
    • 別の名前空間を明示的に指定しない、プロジェクトのルート内のコンポーネント。

以下はサポートされていません

  • global:: 修飾。
  • 部分修飾名。 たとえば、@using BlazorSample をコンポーネントに追加してから、アプリの Shared フォルダー (Shared/NavMenu.razor) の NavMenuコンポーネントを <Shared.NavMenu></Shared.NavMenu> で参照することはできません。

部分クラスのサポート

コンポーネントは C# 部分クラスとして生成され、次のいずれかの方法を使用して作成されます。

  • 1 つのファイルには、1 つまたは複数の @code ブロックで定義されている C# コード、HTML マークアップ、および Razor マークアップが含まれています。 Blazor プロジェクト テンプレートでは、この 1 つのファイルの方法を使用してコンポーネントを定義します。
  • HTML および Razor マークアップは、Razor ファイル (.razor) に配置されます。 C# コードは、部分クラスとして定義されている分離コード ファイル (.cs) に配置されます。

メモ

コンポーネント固有のスタイルを定義するコンポーネント スタイル シートは、個別のファイル (.css) です。 Blazor の CSS 分離については、「ASP.NET Core Blazor の CSS の分離」をご覧ください。

次の例は、Blazor プロジェクト テンプレートから生成されたアプリ内の @code ブロックを含む既定の Counter コンポーネントを示しています。 マークアップと C# コードは同じファイル内にあります。 これは、コンポーネントの作成で最も一般的に使用される方法です。

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

次の Counter コンポーネントでは、部分クラスで分離コード ファイルを使用して、C# コードから HTML と Razor マークアップが分割されます。 一部の組織や開発者は、C# コードからマークアップを分割して、作業方法に合わせてコンポーネント コードを整理することが好まれます。 たとえば、組織の UI エキスパートは、コンポーネントの C# ロジックに取り組む別の開発者とは別に、プレゼンテーション レイヤーで作業できます。 この方法は、自動生成されたコードまたはソース ジェネレーターを使用する場合にも役立ちます。 詳細については、「部分クラスとメソッド (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++;
        }
    }
}

_Imports.razor ファイルの @using ディレクティブは、C# ファイル (.cs) ではなく Razor ファイル (.razor) にのみ適用されます。 必要に応じて、部分クラス ファイルに名前空間を追加します。

コンポーネントで使用される一般的な名前空間は次のとおりです。

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;

一般的な名前空間には、アプリの名前空間と、そのアプリの Components フォルダーに対応する名前空間も含まれます。

using BlazorSample;
using BlazorSample.Components;

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;

一般的な名前空間には、アプリの名前空間と、そのアプリの Shared フォルダーに対応する名前空間も含まれます。

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;

一般的な名前空間には、アプリの名前空間と、そのアプリの Shared フォルダーに対応する名前空間も含まれます。

using BlazorSample;
using BlazorSample.Shared;

基本クラスの指定

@inherits ディレクティブは、コンポーネントの基底クラスを指定するために使用されます。 C# ロジックからのみマークアップを分割する部分クラスを使用するのとは異なり、基底クラスを使用すると、基底クラスのプロパティとメソッドを共有するコンポーネントのグループ全体で使用する C# コードを継承できます。 基底クラスを使用すると、アプリのコードの冗長性が低下し、クラス ライブラリから複数のアプリに基本コードを提供する場合に便利です。 詳細については、「C# と .NET での継承」を参照してください。

次の例では、BlazorRocksBase1 基底クラスは 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!";
}

ルーティング

Blazor でのルーティングは、@page ディレクティブを使用するアプリ内のアクセス可能な各コンポーネントへのルート テンプレートを提供することで実現します。 @page ディレクティブを含む Razor ファイルがコンパイルされると、生成されたクラスに、ルート テンプレートを指定する RouteAttribute が指定されます。 実行時に、ルーターによって RouteAttribute を持つコンポーネント クラスが検索され、要求された URL に一致するルート テンプレートを使用するコンポーネントがレンダリングされます。

次の HelloWorld コンポーネントでは、/hello-world のルート テンプレートを使用し、コンポーネントのレンダリングされた Web ページに相対 URL /hello-worldでアクセスします。

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>

コンポーネントをアプリの UI ナビゲーションに追加するかどうかに関係なく、前のコンポーネントはブラウザーの /hello-world で読み込まれます。 必要に応じて、コンポーネントを NavMenu コンポーネントに追加し、そのコンポーネントへのリンクがアプリの UI ベースのナビゲーションに表示されるようにすることができます。

前の HelloWorld コンポーネントでは、NavLink コンポーネントを NavMenu コンポーネントに追加できます。 NavLinkNavMenu コンポーネントの説明など詳しくは、「ASP.NET Core の Blazor ルーティングとナビゲーション」をご覧ください。

マークアップ

コンポーネントの UI は、Razor マークアップ、C#、HTML で構成される Razor 構文を使用して定義されます。 アプリがコンパイルされると、HTML マークアップと C# のレンダリング ロジックはコンポーネント クラスに変換されます。 生成されたクラスの名前は、ファイルの名前と一致します。

コンポーネント クラスのメンバーは、1 つまたは複数の @code ブロック内で定義されます。 @code ブロックでは、コンポーネントの状態が指定され、C# で処理されます:

  • プロパティとフィールドの初期化子。
  • 親コンポーネントとルート パラメーターによって渡される引数からのパラメーター値。
  • ユーザー イベント処理、ライフサイクル イベント、およびカスタム コンポーネント ロジックのメソッド。

コンポーネント メンバーは、@ 記号で始まる C# 式を使ったレンダリング ロジックで使用されます。 たとえば、フィールド名の前に @ を付けることによって、C# フィールドがレンダリングされます。 次の Markup コンポーネントでは、以下を評価およびレンダリングします。

  • 見出し要素の CSS プロパティ値 headingFontStylefont-style
  • 見出し要素のコンテンツの headingText

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

メモ

Blazor ドキュメント全体の例では、プライベート メンバーの private アクセス修飾子を指定します。 プライベート メンバーは、コンポーネントのクラスにスコープ指定されます。 しかし、C# では、アクセス修飾子が存在しない場合、private アクセス修飾子が想定されるため、独自のコードでメンバーを "private" として明示的にマークすることは省略可能です。 アクセス修飾子の詳細については、「アクセス修飾子 (C# プログラミング ガイド)」を参照してください。

Blazor フレームワークでは、コンポーネントを内部的にレンダリング ツリーとして処理します。これは、コンポーネントの DOM とカスケード スタイル シートオブジェクト モデル (CSSOM) の組み合わせです。 コンポーネントが最初にレンダリングされた後に、そのコンポーネントのレンダリング ツリーがイベントに応じて再生成されます。 Blazor によって新旧のレンダリング ツリーが比較され、表示目的でブラウザーの DOM に変更がすべて適用されます。 詳しくは、「ASP.NET Core Razor コンポーネントのレンダリング」をご覧ください。

C# コントロール構造体、ディレクティブ、およびディレクティブ属性の Razor 構文は小文字です (例: @if@code@bind)。 プロパティ名は大文字です (例: LayoutComponentBase.Body@Body)。

非同期メソッド (async) では、void を返すことはサポートされていません

Blazor フレームワークでは、void を返す非同期メソッド (async) は追跡されません。 その結果、void が返された場合、例外はキャッチされません。 非同期メソッドからは、常に Task が返されます。

入れ子になったコンポーネント

コンポーネントには、HTML 構文を使用して宣言することで、他のコンポーネントを含めることができます。 コンポーネントを使うためのマークアップは、そのコンポーネントの種類をタグ名とする HTML タグのようになります。

他のコンポーネントで見出しを表示するために使用できる次の Heading コンポーネントについて考えてみます。

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

HeadingExample コンポーネント内の次のマークアップでは、<Heading /> タグが表示される位置に、前の 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 />

同じ名前空間内のコンポーネント名と一致しない最初の文字が大文字の HTML 要素がコンポーネントに含まれている場合、要素に予期しない名前が付いていることを示す警告が出力されます。 コンポーネントの名前空間に @using ディレクティブを追加すると、コンポーネントを使用できるようになり、警告が解決されます。 詳細については、「コンポーネント名、クラス名、および名前空間 」セクションを参照してください。

このセクションに示されている Heading コンポーネントの例には @page ディレクティブがないため、Heading コンポーネントには、ブラウザーで直接要求を使用してユーザーが直接アクセスすることはできません。 しかし、@page ディレクティブを持つコンポーネントは、他のコンポーネントの入れ子にすることができます。 Razor ファイルの先頭に @page "/heading" を含めることによって Heading コンポーネントに直接アクセスできた場合は、/heading/heading-example の両方でブラウザー要求に対してコンポーネントがレンダリングされます。

コンポーネントのパラメーター

''コンポーネント パラメーター'' によりデータがコンポーネントに渡されます。これらのパラメーターは、[Parameter] 属性を指定したコンポーネント クラス上で、パブリック C# プロパティを使用して定義されます。 次の例では、組み込みの参照型 (System.String) とユーザー定義の参照型 (PanelBody) がコンポーネント パラメーターとして渡されます。

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

警告

コンポーネント パラメーターの初期値の指定はサポートされていますが、コンポーネントが初めてレンダリングされた後に独自のパラメーターに書き込むコンポーネントは作成しないでください。 詳細については、「ASP.NET Core Blazor でパラメーターを上書きしないようにする」を参照してください。

ParameterChild コンポーネントの Title および Body コンポーネント パラメーターは、コンポーネントのインスタンスをレンダリングする HTML タグの引数によって設定されます。 次の ParameterParent コンポーネントでは、2 つの ParameterChild コンポーネントがレンダリングされます。

  • 1 つ目の ParameterChild コンポーネントは、パラメーター引数を指定せずにレンダリングされます。
  • 2 つ目の ParameterChild コンポーネントでは、明示的な C# 式を使用して PanelBody のプロパティの値を設定する ParameterParent コンポーネントからの TitleBody の値を受け取ります。

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

ParameterParent コンポーネントでコンポーネントのパラメーター値が指定されていない場合、ParameterParent コンポーネントの次のレンダリングされた HTML マークアップに ParameterChild コンポーネントの既定値が表示されます。 ParameterParent コンポーネントでコンポーネントのパラメーター値が指定されている場合は、その ParameterChild コンポーネントの既定値が置き換えられます。

メモ

わかりやすくするために、レンダリングされた CSS スタイル クラスは次のレンダリングされた HTML マークアップには表示されていません。

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

C# フィールド、プロパティ、またはメソッドの結果を HTML 属性値としてコンポーネント パラメーターに割り当てます。 属性の値には、通常、パラメーターの型に一致する任意の C# 式を指定できます。 属性値の先頭には Razor 予約@記号を付けることができますが、必須ではありません。

コンポーネント パラメーターが文字列型の場合、属性値は既定で C# 文字列リテラルとして扱われます。 代わりに C# 式を指定する場合は、@ プレフィックスを使用します。

次の ParameterParent2 コンポーネントでは、上記の ParameterChild コンポーネントの 4 つのインスタンスが表示され、それらの Title パラメーター値が次のように設定されます。

  • title フィールドの値。
  • GetTitle C# メソッドの結果。
  • 暗黙的な C# 式を使用する ToLongDateString による長い形式での現在のローカル日付。
  • panelData オブジェクトの Title プロパティ。

HTML5 の仕様によると、ほとんどの場合、パラメーター属性値を囲む引用符は省略可能です。 たとえば、Value="this" の代わりに Value=this を使ってもかまいません。 ただし、覚えやすく、Web ベースのテクノロジで広く採用されているため、引用符を使うことをお勧めします。

このドキュメントのコード例では次にようになっています。

  • 常に引用符を使用します。 例: Value="this"
  • 必要な場合を除き、リテラル以外で @ プレフィックスを使用しないでください。 例: Count="ct": ct は数値型の変数です。 Count="@ct" は有効なスタイルのアプローチですが、ドキュメントと例では規則は採用されていません。
  • Razor 式の外部のリテラルでは、常に @ を回避します。 例: IsFixed="true"。 これにはキーワード (たとえば、this) と null も含まれますが、必要に応じてこれらを使用することもできます。 たとえば、IsFixed="@true" は一般的ではありませんがサポートされています。

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

メモ

C# メンバーをコンポーネント パラメーターに割り当てる場合は、パラメーターの HTML 属性に @ をプレフィックスとして付けないでください。

正解です (Title は文字列パラメーターで、Count は数値型パラメーターです):

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

正しくない:

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

Razor ページ (.cshtml) とは異なり、Blazor では、コンポーネントのレンダリング中に Razor 式で非同期処理を実行することはできません。 これは、Blazor が対話型 UI をレンダリングするように設計されているためです。 対話型 UI の場合、画面には常に何かが表示されている必要があるため、レンダリング フローをブロックしても意味はありません。 代わりに、非同期処理は、いずれかの非同期ライフサイクル イベント中に実行されます。 非同期ライフサイクル イベントが発生するたびに、コンポーネントは再びレンダリングされる可能性があります。 次の Razor 構文はサポートされていません

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

上記の例に含まれるコードでは、アプリのビルド時に "コンパイラ エラー" が発生します。

'await' 演算子は、非同期メソッド内でのみ使用できます。 このメソッドを 'async' 修飾子でマークし、その戻り値の型を 'Task' に変更することを検討してください。

上記の例で非同期的に Title パラメーターの値を取得するには、次の例に示すように、コンポーネントで OnInitializedAsync ライフサイクル イベントを使用できます。

<ParameterChild Title="@title" />

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

詳しくは、「ASP.NET Core Razor コンポーネントのライフサイクル」をご覧ください。

パラメーターに代入するために、明示的な Razor 式を使用してテキストを式の結果と連結することは、サポートされていません。 次の例では、テキスト "Set by " とオブジェクトのプロパティ値を連結しようとしています。 この構文は Razor ページ (.cshtml) でサポートされていますが、コンポーネントで子の Title パラメーターに代入する場合は無効です。 次の Razor 構文はサポートされていません

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

上記の例に含まれるコードでは、アプリのビルド時に "コンパイラ エラー" が発生します。

コンポーネント属性では、複合コンテンツ (C# とマークアップの混合) はサポートされていません。

合成値の割り当てをサポートするには、メソッド、フィールド、またはプロパティを使用します。 次の例では、C# メソッド GetTitle で、"Set by " とオブジェクトのプロパティ値の連結を実行します。

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

詳細については、「ASP.NET Coreの Razor 構文リファレンス」を参照してください。

警告

コンポーネント パラメーターの初期値の指定はサポートされていますが、コンポーネントが初めてレンダリングされた後に独自のパラメーターに書き込むコンポーネントは作成しないでください。 詳細については、「ASP.NET Core Blazor でパラメーターを上書きしないようにする」を参照してください。

コンポーネント パラメーターは "自動プロパティ" として宣言する必要があります。つまり、それらの getset アクセサーにカスタム ロジックを含めることはできません。 たとえば、次の StartData プロパティは自動プロパティです。

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

get または set アクセサーにカスタム ロジックを配置しないでください。なぜなら、コンポーネント パラメーターの目的は、親コンポーネントから子コンポーネントに情報をフローさせるためのチャネルとして使用することだけだからです。 子コンポーネントのプロパティの set アクセサーに、親コンポーネントの再レンダリングが発生する原因となるロジックが含まれている場合、レンダリングの無限ループが発生します。

受け取ったパラメーター値を変換するには、次のようにします。

  • パラメーター プロパティは、指定された生データを表す自動プロパティのままにしておきます。
  • 異なるプロパティまたはメソッドを作成し、パラメーター プロパティに基づいて変換されたデータを指定します。

OnParametersSetAsync をオーバーライドし、新しいデータを受け取るたびに受け取ったパラメーターを変換します。

コンポーネント パラメーターに初期値を書き込むことはサポートされています。これは、初期値の代入によって、Blazor の自動コンポーネント レンダリングが妨げられることはないからです。 DateTime.Now での現在のローカル DateTimeStartData への次の代入は、コンポーネントで有効な構文です。

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

DateTime.Now の初期代入後は、開発者コードで StartData に値を代入しないでください。 詳細については、「ASP.NET Core Blazor でパラメーターを上書きしないようにする」を参照してください。

[EditorRequired] 属性を適用して、必要なコンポーネント パラメーターを指定します。 パラメーター値が指定されていない場合、エディターまたはビルド ツールによってユーザーに警告が表示される場合があります。 この属性は、[Parameter] 属性でもマークされているプロパティでのみ有効です。 EditorRequiredAttribute は、デザイン時とアプリのビルド時に適用されます。 この属性は実行時に適用されません。また、null 以外のパラメーター値は保証されません。

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

単一行属性リストもサポートされています。

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

コンポーネント パラメーターのプロパティで required 修飾子 または init アクセサー を使用しないでください。 コンポーネントは、通常、リフレクションを使用してインスタンス化され、パラメーター値が割り当てられます。これにより、initrequired が作成されるように設計された保証がバイパスされます。 [EditorRequired] 属性を適用して、必要なコンポーネント パラメーターを指定します。

ParameterView.SetParameterProperties でコンポーネント パラメーターの値を設定するとリフレクションが使用されるため、コンポーネント パラメータープロパティで init アクセサーを使用しないでください。これは init 専用セッター制限をバイパスします。 [EditorRequired] 属性を適用して、必要なコンポーネント パラメーターを指定します。

ParameterView.SetParameterProperties でコンポーネント パラメーターの値を設定するとリフレクションが使用されるため、コンポーネント パラメータープロパティで init アクセサーを使用しないでください。これは init 専用セッター制限をバイパスします。

Tuples (API ドキュメント) は、コンポーネントのパラメーターと RenderFragment 型に対してサポートされています。 次のコンポーネント パラメーターの例では、Tuple で 3 つの値を渡します。

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

次の例に示すように、名前付きタプルがサポートされています:

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

引用 ©2005 Universal Pictures: Serenity (Nathan Fillion)

Tuples (API ドキュメント) は、コンポーネントのパラメーターと RenderFragment 型に対してサポートされています。 次のコンポーネント パラメーターの例では、Tuple で 3 つの値を渡します。

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

次の例に示すように、名前付きタプルがサポートされています:

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

引用 ©2005 Universal Pictures: Serenity (Nathan Fillion)

ルート パラメーター

コンポーネントでは、@page ディレクティブのルート テンプレートでルート パラメーターを指定できます。 Blazor ルーターでは、ルート パラメーターを使用して、対応するコンポーネント パラメーターが設定されます。

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

詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」の「ルート パラメーター」セクションを参照してください。 オプションのルート パラメーターもサポートされており、同じセクションで説明しています。 複数のフォルダー境界を越えるパスを取得するキャッチオールのルート パラメーター ({*pageRoute}) について詳しくは、「ASP.NET Core の Blazor ルーティングとナビゲーション」の「キャッチオールのルート パラメーター」を参照してください。

詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」の「ルート パラメーター」セクションを参照してください。 オプションのルート パラメーターはサポートされていないため、2 つの@page ディレクティブが必要です (詳細については、「ルート パラメーター」セクションを参照してください)。 複数のフォルダー境界を越えるパスを取得するキャッチオールのルート パラメーター ({*pageRoute}) について詳しくは、「ASP.NET Core の Blazor ルーティングとナビゲーション」の「キャッチオールのルート パラメーター」を参照してください。

子コンテンツのレンダリング フラグメント

コンポーネントでは、別のコンポーネントのコンテンツを設定できます。 代入コンポーネントでは、子コンポーネントの開始および終了タグの間にコンテンツを指定します。

次の例では、RenderFragmentChild コンポーネントに、RenderFragment としてレンダリングする UI のセグメントを表す ChildContent コンポーネント パラメーターがあります。 コンポーネントの Razor マークアップ内の ChildContent の位置は、コンテンツが最終的な HTML 出力にレンダリングされる場所です。

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

重要

RenderFragment コンテンツを受け取るプロパティは、規則によって ChildContent という名前にする必要があります。

イベント コールバックは、RenderFragment ではサポートされていません。

次のコンポーネントは、子コンポーネントの開始および終了タグ内にコンテンツを配置して、RenderFragmentChild をレンダリングするためのコンテンツを提供します。

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>

Blazor による子コンテンツのレンダリング方法により、for ループ内のコンポーネントのレンダリングでは、インクリメントするループ変数が RenderFragmentChild コンポーネントのコンテンツ内で使用されている場合、ローカル インデックス変数が必要になります。 次の例は、前の親コンポーネントに追加できます。

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

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

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

または、for ループではなく、Enumerable.Range と共に foreach ループを使用します。 次の例は、前の親コンポーネントに追加できます。

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

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

レンダリング フラグメントは、Blazor アプリ全体で子コンテンツをレンダリングするために使用され、次の記事と記事のセクションの例と共に説明されています。

再利用可能なレンダリング ロジックのフラグメントをレンダリングする

レンダリング ロジックを再利用するための方法として、子コンポーネントを純粋に取り出すことができます。 任意のコンポーネントの @code ブロックで、RenderFragment を定義し、必要に応じて任意の場所からフラグメントをレンダリングします。

@RenderWelcomeInfo

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

@RenderWelcomeInfo

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

詳細については、レンダリング ロジックの再利用に関するページを参照してください。

コンポーネントへの参照をキャプチャする

コンポーネント参照を使用すると、コマンドを発行するためのコンポーネント インスタンスを参照することができます。 コンポーネント参照をキャプチャするには:

  • 子コンポーネントに @ref 属性を追加します。
  • 子コンポーネントと同じ型のフィールドを定義します。

コンポーネントがレンダリングされると、フィールドにコンポーネント インスタンスが設定されます。 その後、そのインスタンスに対して .NET メソッドを呼び出すことができます。

ChildMethod が呼び出されたときにメッセージをログに記録する次の ReferenceChild コンポーネントについて考えてみます。

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

コンポーネント参照は、コンポーネントがレンダリングされた後にのみ設定され、その出力には ReferenceChild 要素が含まれます。 コンポーネントがレンダリングされるまで、参照するものはありません。 クリック イベントが割り当てられた時点で参照変数が割り当てられない可能性があるため、参照先コンポーネント メソッドをイベント ハンドラーに直接呼び出すこと (たとえば @onclick="childComponent!.ChildMethod(5)" のように) はしないでください。

コンポーネントのレンダリングが終了した後にコンポーネント参照を操作するには、OnAfterRender または OnAfterRenderAsync メソッドを使用します。

次の例では、前の 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);
    }
}

コンポーネント参照の取り込みでは、要素参照の取り込みと同様の構文を使用しますが、コンポーネント参照の取り込みは JavaScript 相互運用機能ではありません。 コンポーネント参照は、JavaScript コードに渡されません。 コンポーネント参照は、.NET コードでのみ使用されます。

重要

子コンポーネントの状態を変えるためにコンポーネント参照を使用しないでください。 代わりに、通常の宣言型コンポーネント パラメーターを使用して、子コンポーネントにデータを渡します。 コンポーネント パラメーターを使用すると、子コンポーネントが正しいタイミングで自動的にレンダリングされます。 詳しくは、「コンポーネントのパラメーター」セクションと、記事「ASP.NET Core Blazor データ バインディング」をご覧ください。

属性を適用する

属性は、@attribute ディレクティブを使用してコンポーネントに適用できます。 次の例では、[Authorize] 属性をコンポーネントのクラスに適用しています。

@page "/"
@attribute [Authorize]

条件付き HTML 要素属性

HTML 要素属性プロパティは、.NET 値に基づいて条件付きで設定されます。 値が false または null の場合、プロパティは設定されません。 値が true の場合は、プロパティが設定されます。

次の例では、IsCompleted により、<input> 要素の checked プロパティが設定されるかどうかが決定されます。

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

詳細については、「ASP.NET Coreの Razor 構文リファレンス」を参照してください。

警告

.NET 型が bool の場合、aria-pressed などの一部の HTML 属性が正しく機能しません。 そのような場合は、bool ではなく string 型を使用します。

生 HTML

通常、文字列は DOM テキスト ノードを使用してレンダリングされます。つまり、それらに含まれている可能性のあるすべてのマークアップが無視され、リテラル テキストとして扱われます。 生 HTML をレンダリングするには、HTML コンテンツを MarkupString 値にラップします。 値は HTML または SVG として解析され、DOM に挿入されます。

警告

信頼されていないソースから構築された生 HTML をレンダリングすることは、セキュリティ リスクであるため、常に避ける必要があります。

次の例では、MarkupString 型を使用して、コンポーネントのレンダリングされた出力に静的 HTML コンテンツのブロックを追加しています。

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 テンプレート

レンダリング フラグメントは、UI スニペットを定義するための Razor テンプレート構文を使用して定義できます。 Razor テンプレートでは次の形式を使用します。

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

次の例では、RenderFragmentRenderFragment<TValue> の値を指定し、コンポーネント内にテンプレートを直接レンダリングする方法を示しています。 レンダリング フラグメントは、引数としてテンプレート コンポーネントに渡すこともできます。

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

前のコードのレンダリングされた結果:

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

静的な資産

静的資産の場合、Blazor では ASP.NET Core アプリの規則に従います。 静的資産は、プロジェクトの web root (wwwroot) フォルダー、または wwwroot フォルダーの下のフォルダーにあります。

静的アセットの Web ルートを参照するには、ベース相対パス (/) を使用します。 次の例では、logo.png が物理的に {PROJECT ROOT}/wwwroot/images フォルダーに配置されています。 {PROJECT ROOT} は、アプリのプロジェクト ルートです。

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

コンポーネントでは、チルダ スラッシュ表記 (~/) はサポートされていません

アプリのベース パスの設定について詳しくは、「ASP.NET Core Blazor のホストと展開」をご覧ください。

タグ ヘルパーはコンポーネントでサポートされない

Tag Helpers はコンポーネントでサポートされていません。 Blazor にタグ ヘルパーのような機能を提供するには、タグ ヘルパーと同じ機能を持つコンポーネントを作成し、代わりにそのコンポーネントを使用します。

スケーラブル ベクター グラフィックス (SVG) イメージ

Blazor は HTML をレンダリングするため、スケーラブル ベクター グラフィックス (SVG) 画像 (.svg) などのブラウザーでサポートされている画像は、<img> タグを介してサポートされます。

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

同様に、SVG 画像は、スタイルシート ファイル (.css) の CSS 規則でサポートされています。

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

SVG 内の任意の HTML の表示に Blazor は <foreignObject> 要素をサポートしています。 このマークアップでは、任意の HTML、RenderFragment、または Razor コンポーネントを表すことができます。

その具体的な例を次に示します:

  • string の表示 (@message)。
  • <input> 要素と value フィールドを使用した双方向のバインディング。
  • 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;
}

空白文字のレンダリング動作

@preservewhitespace ディレクティブが true の値と共に使用されている場合を除き、既定では、次の場合に余分な空白が削除されます:

  • 要素内の先頭または末尾。
  • RenderFragment/RenderFragment<TValue> パラメーター内の先頭または末尾 (たとえば、別のコンポーネントに渡された子コンテンツ)。
  • @if または @foreach のような、C# コード ブロックの前か後にある。

空白文字の削除は、white-space: pre などの CSS ルールを使用するときに、レンダリングされた出力に影響を与えることがあります。 このパフォーマンスの最適化を無効にして、空白を保持するには、次のいずれかの操作を実行します。

  • Razor ファイル (.razor) の先頭に @preservewhitespace true ディレクティブを追加し、特定のコンポーネントに設定を適用する。
  • _Imports.razor ファイル内に @preservewhitespace true ディレクティブを追加し、サブディレクトリまたはプロジェクト全体に設定を適用する。

ほとんどの場合、アプリでは一般的に通常の動作が続行されるため (ただし、速くなります)、何の措置も必要ありません。 空白文字を削除すると特定のコンポーネントでレンダリングの問題が発生する場合は、そのコンポーネントで @preservewhitespace true を使用し、この最適化を無効にします。

空白文字は、コンポーネントのソース マークアップに保持されます。 空白文字のみのテキストは、視覚効果がないときでも、ブラウザーの DOM にレンダリングされます。

次のコンポーネント マークアップについて考えてみます。

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

前の例では、次の不要な空白文字がレンダリングされます。

  • @foreach コード ブロックの外側。
  • <li> 要素の前後。
  • @item.Text 出力の前後。

100 項目のリストの場合、空白文字の領域が 400 を超えます。 レンダリングされる出力に視覚的に影響する余分な空白文字はありません。

コンポーネントの静的 HTML をレンダリングする場合、タグ内の空白文字は保持されません。 たとえば、コンポーネント <img> ファイル (.razor) で次の Razor タグのレンダリングされる出力を表示します。

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

前のマークアップからの空白文字は保持されません。

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

ルート コンポーネント

"ルート Razor コンポーネント" ("ルート コンポーネント") は、アプリによって作成されたコンポーネント階層の最初に読み込まれるコンポーネントです。

Blazor Web アプリ プロジェクト テンプレートから作成されたアプリでは、App コンポーネント (App.razor) は、サーバー側 Program ファイルで MapRazorComponents<TRootComponent> 呼び出し用に宣言された型パラメーターによって既定のルート コンポーネントとして指定されます。 次の例は、ルート コンポーネントとしての App コンポーネントの使用を示しています。これは、Blazor プロジェクト テンプレートから作成されたアプリの既定値です:

app.MapRazorComponents<App>();

Note

ルート コンポーネントを対話型にすること (App コンポーネントなど) はサポートされていません。

Blazor Server プロジェクト テンプレートから作成されたアプリでは、App コンポーネント (App.razor) は、コンポーネント タグ ヘルパーを使用して Pages/_Host.cshtml の既定のルート コンポーネントとして指定されます:

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

Blazor WebAssembly プロジェクト テンプレートから作成されたアプリでは、App コンポーネント (App.razor) が Program ファイル内の既定のルート コンポーネントとして指定されます:

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

上記のコードでは、CSS セレクター #app は、App コンポーネントが appid を持つ wwwroot/index.html<div>に対して指定されていることを示しています:

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

MVC アプリと Razor Pages アプリでは、コンポーネント タグ ヘルパーを使用して、静的にレンダリングされた Blazor WebAssembly ルート コンポーネントを登録することもできます:

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

静的にレンダリングされたコンポーネントは、アプリにのみ追加できます。 後で削除または更新することはできません。

詳細については、次のリソースを参照してください。