ASP.NET Core Razor コンポーネントの作成と使用Create and use ASP.NET Core Razor components

作成者: Luke LathamDaniel RothBy Luke Latham and Daniel Roth

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

Blazor アプリは コンポーネントを使用してビルドします。 apps are built using components. コンポーネントは、ページ、ダイアログ、フォームなどのユーザー インターフェイス (UI) の自己完結型のチャンクです。A component is a self-contained chunk of user interface (UI), such as a page, dialog, or form. コンポーネントには、データの挿入や UI イベントへの応答に必要な HTML マークアップと、処理ロジックが含まれます。A component includes HTML markup and the processing logic required to inject data or respond to UI events. コンポーネントは、柔軟性があり、軽量です。Components are flexible and lightweight. それらを入れ子にしたり、再利用したり、プロジェクト間で共有したりできます。They can be nested, reused, and shared among projects.

コンポーネント クラスComponent classes

コンポーネントは、C# と HTML マークアップの組み合わせを使用して、Razor コンポーネント ファイル ( .razor) で実装します。Components are implemented in Razor component files (.razor) using a combination of C# and HTML markup. Blazor のコンポーネントは、正式には Razor コンポーネント と呼ばれます。A component in Blazor is formally referred to as a Razor component.

コンポーネントの名前は、大文字で始める必要があります。A component's name must start with an uppercase character. たとえば、MyCoolComponent.razor は有効で、myCoolComponent.razor は無効です。For example, MyCoolComponent.razor is valid, and myCoolComponent.razor is invalid.

コンポーネントの UI は、HTML を使用して定義します。The UI for a component is defined using HTML. 動的なレンダリング ロジック (たとえばループ、条件、式) が、Razor と呼ばれる埋め込みの C# 構文を使って追加されています。Dynamic rendering logic (for example, loops, conditionals, expressions) is added using an embedded C# syntax called Razor. アプリがコンパイルされると、HTML マークアップと C# のレンダリング ロジックはコンポーネント クラスに変換されます。When an app is compiled, the HTML markup and C# rendering logic are converted into a component class. 生成されたクラスの名前は、ファイルの名前と一致します。The name of the generated class matches the name of the file.

コンポーネント クラスのメンバーは、@code ブロック内で定義されています。Members of the component class are defined in an @code block. @code ブロックには、イベント処理のメソッド、またはその他のコンポーネント ロジックを定義するためのメソッドによって、コンポーネントの状態 (プロパティ、フィールド) を指定します。In the @code block, component state (properties, fields) is specified with methods for event handling or for defining other component logic. 複数の @code ブロックが許容されます。More than one @code block is permissible.

コンポーネント メンバーは、@ で始まる C# 式を使用して、コンポーネントのレンダリング ロジックの一部として使用できます。Component members can be used as part of the component's rendering logic using C# expressions that start with @. たとえば、フィールド名の前に @ を付けることによって、C# フィールドがレンダリングされます。For example, a C# field is rendered by prefixing @ to the field name. 次の例では、以下のように評価され、レンダリングされます。The following example evaluates and renders:

  • _headingFontStylefont-style の CSS プロパティ値に。_headingFontStyle to the CSS property value for font-style.
  • _headingText<h1> 要素のコンテンツに。_headingText to the content of the <h1> element.
<h1 style="font-style:@_headingFontStyle">@_headingText</h1>

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

コンポーネントが最初にレンダリングされた後に、コンポーネントがイベントに応答して、レンダリング ツリーを再生成します。After the component is initially rendered, the component regenerates its render tree in response to events. Blazor によって新旧のレンダリング ツリーが比較され、ブラウザーのドキュメント オブジェクト モデル (DOM) に変更が適用されます。 then compares the new render tree against the previous one and applies any modifications to the browser's Document Object Model (DOM).

コンポーネントは通常の C# クラスであり、プロジェクト内の任意の場所に配置できます。Components are ordinary C# classes and can be placed anywhere within a project. Web ページを生成するコンポーネントは、通常、Pages フォルダーに存在します。Components that produce webpages usually reside in the Pages folder. ページ以外のコンポーネントは、多くの場合に、Shared フォルダー、またはプロジェクトに追加されたカスタム フォルダーに配置されます。Non-page components are frequently placed in the Shared folder or a custom folder added to the project.

一般に、コンポーネントの名前空間は、アプリのルート名前空間と、アプリ内のコンポーネントの場所 (フォルダー) から派生します。Typically, a component's namespace is derived from the app's root namespace and the component's location (folder) within the app. アプリのルート名前空間が BlazorApp で、Counter コンポーネントが Pages フォルダーに存在する場合:If the app's root namespace is BlazorApp and the Counter component resides in the Pages folder:

  • Counter コンポーネントの名前空間は BlazorApp.Pages になります。The Counter component's namespace is BlazorApp.Pages.
  • コンポーネントの完全修飾型名は BlazorApp.Pages.Counter になります。The fully qualified type name of the component is BlazorApp.Pages.Counter.

詳細については、「コンポーネントのインポート」セクションを参照してください。For more information, see the Import components section.

カスタム フォルダーを使用するには、カスタム フォルダーの名前空間を親コンポーネントまたはアプリの _Imports.razor ファイルに追加します。To use a custom folder, add the custom folder's namespace to either the parent component or to the app's _Imports.razor file. たとえば、アプリのルート名前空間が BlazorApp である場合、次の名前空間によって、Components フォルダー内のコンポーネントを使用できます。For example, the following namespace makes components in a Components folder available when the app's root namespace is BlazorApp:

@using BlazorApp.Components

静的な資産Static assets

Blazor は、プロジェクトの Web ルート (wwwroot) フォルダーに静的アセットを配置する ASP.NET Core アプリの規則に従います。 follows the convention of ASP.NET Core apps placing static assets under the project's web root (wwwroot) folder.

静的アセットの Web ルートを参照するには、ベース相対パス (/) を使用します。Use a base-relative path (/) to refer to the web root for a static asset. 次の例では、logo.png が物理的に {PROJECT ROOT}/wwwroot/images フォルダーに置かれています。In the following example, logo.png is physically located in the {PROJECT ROOT}/wwwroot/images folder:

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

Razor コンポーネントでは、チルダ スラッシュ表記 (~/) はサポートされていませんRazor components do not support tilde-slash notation (~/).

アプリのベース パスの設定の詳細については、「ASP.NET Core Blazor のホストと展開」を参照してください。For information on setting an app's base path, see ASP.NET Core Blazor のホストと展開.

タグ ヘルパーはコンポーネントでサポートされないTag Helpers aren't supported in components

タグ ヘルパー は、Razor コンポーネント ( .razor ファイル) でサポートされていません。Tag Helpers aren't supported in Razor components (.razor files). Blazor にタグ ヘルパーのような機能を提供するには、タグ ヘルパーと同じ機能を持つコンポーネントを作成し、代わりにそのコンポーネントを使用します。To provide Tag Helper-like functionality in Blazor, create a component with the same functionality as the Tag Helper and use the component instead.

コンポーネントを使うUse components

コンポーネントには、HTML 要素構文を使用して宣言することで、他のコンポーネントを含めることができます。Components can include other components by declaring them using HTML element syntax. コンポーネントを使うためのマークアップは、そのコンポーネントの種類をタグ名とする HTML タグのようになります。The markup for using a component looks like an HTML tag where the name of the tag is the component type.

Index.razor の次のマークアップは、HeadingComponent インスタンスをレンダリングします。The following markup in Index.razor renders a HeadingComponent instance:

<HeadingComponent />

Components/HeadingComponent.razor:Components/HeadingComponent.razor:

@using System.Globalization
@*
    The 'using' directive makes System.Globalization available to 
    the component. System.Globalization provides a method for 
    converting a string into title case (capitalizes the first 
    letter of every word in a string), which is used to convert a 
    a string into title case for a heading.
*@

@*
    Heading text is rendered by evaluating the _headingText field. 
    The font-style of the heading is rendered by evaluating the 
    _headingFontStyle field.
*@
<h1 style="font-style:@_headingFontStyle">@_headingText</h1>

<form>
    <div>
        @*
            A check box sets the font style and is bound to the 
            _italicsCheck field.
        *@
        <input type="checkbox" id="italicsCheck" 
               @bind="_italicsCheck" />
        <label class="form-check-label" 
            for="italicsCheck">Use italics</label>
    </div>

    @*
        When the form is submitted, the onclick event executes 
        the UpdateHeading method.
    *@
    <button type="button" class="btn btn-primary" @onclick="UpdateHeading">
        Update heading
    </button>
</form>

@code {
    private static TextInfo _tinfo = CultureInfo.CurrentCulture.TextInfo;
    private string _headingText = 
        _tinfo.ToTitleCase("welcome to blazor!");
    private string _headingFontStyle = "normal";
    private bool _italicsCheck = false;

    // When UpdateHeading is executed, _italicsCheck determines 
    // the value of _headingFontStyle to set the font style of the 
    // heading.
    public void UpdateHeading()
    {
        _headingFontStyle = _italicsCheck ? "italic" : "normal";
    }
}

コンポーネント名と一致しない最初の文字が大文字の HTML 要素がコンポーネントに含まれている場合、要素に予期しない名前が付いていることを示す警告が出力されます。If a component contains an HTML element with an uppercase first letter that doesn't match a component name, a warning is emitted indicating that the element has an unexpected name. コンポーネントの名前空間に @using ディレクティブを追加すると、コンポーネントを使用できるようになり、警告が解決されます。Adding an @using directive for the component's namespace makes the component available, which resolves the warning.

ルーティングRouting

Blazor でのルーティングは、アプリ内のアクセス可能な各コンポーネントへのルート テンプレートを提供することで実現します。Routing in Blazor is achieved by providing a route template to each accessible component in the app.

@page ディレクティブを含む Razor ファイルがコンパイルされると、生成されたクラスに、ルート テンプレートを指定する RouteAttribute が指定されます。When a Razor file with an @page directive is compiled, the generated class is given a RouteAttribute specifying the route template. 実行時に、ルーターによって RouteAttribute を持つコンポーネント クラスが検索され、要求された URL に一致するルート テンプレートを使用するコンポーネントがレンダリングされます。At runtime, the router looks for component classes with a RouteAttribute and renders whichever component has a route template that matches the requested URL.

@page "/ParentComponent"

...

詳細については、「ASP.NET Core Blazor のルーティング」を参照してください。For more information, see ASP.NET Core Blazor のルーティング.

パラメーターParameters

ルート パラメーターRoute parameters

コンポーネントでは、@page ディレクティブに指定されたルート テンプレートからルート パラメーターを受け取ることができます。Components can receive route parameters from the route template provided in the @page directive. ルーターでは、ルート パラメーターを使用して、対応するコンポーネント パラメーターが設定されます。The router uses route parameters to populate the corresponding component parameters.

Pages/RouteParameter.razor:Pages/RouteParameter.razor:

@page "/RouteParameter"
@page "/RouteParameter/{text}"

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

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

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}

オプションのパラメーターはサポートされていないため、前の例では 2 つの @page ディレクティブが適用されます。Optional parameters aren't supported, so two @page directives are applied in the preceding example. 1 つ目は、パラメーターを指定せずにコンポーネントへの移動を許可します。The first permits navigation to the component without a parameter. 2 番目の @page ディレクティブは、{text} ルート パラメーターを受け取り、その値を Text プロパティに割り当てます。The second @page directive receives the {text} route parameter and assigns the value to the Text property.

複数のフォルダー境界をまたいだパスをキャプチャするキャッチオール パラメーター構文 (*/**) は、Razor コンポーネント ( .razor) ではサポートされていませんCatch-all parameter syntax (*/**), which captures the path across multiple folder boundaries, is not supported in Razor components (.razor).

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

コンポーネントには、コンポーネント パラメーターを指定でき、これは [Parameter] 属性を指定したコンポーネント クラスで、パブリック プロパティを使用して定義します。Components can have component parameters, which are defined using public properties on the component class with the [Parameter] attribute. マークアップ内でコンポーネントの引数を指定するには、属性を使います。Use attributes to specify arguments for a component in markup.

Components/ChildComponent.razor:Components/ChildComponent.razor:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

サンプル アプリの次の例では、ParentComponent によって ChildComponentTitle プロパティの値を設定しています。In the following example from the sample app, the ParentComponent sets the value of the Title property of the ChildComponent.

Pages/ParentComponent.razor:Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClickCallback="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

子コンテンツChild content

コンポーネントでは、別のコンポーネントのコンテンツを設定できます。Components can set the content of another component. 割り当てコンポーネントでは、受信コンポーネントを指定するタグ間にコンテンツを指定します。The assigning component provides the content between the tags that specify the receiving component.

次の例では、ChildComponent に、レンダリングする UI のセグメントを表す RenderFragment を表す ChildContent プロパティがあります。In the following example, the ChildComponent has a ChildContent property that represents a RenderFragment, which represents a segment of UI to render. コンテンツをレンダリングする必要があるコンポーネントのマークアップに、ChildContent の値を配置します。The value of ChildContent is positioned in the component's markup where the content should be rendered. ChildContent の値は、親コンポーネントから受け取られ、ブートストラップ パネルの panel-body 内にレンダリングされます。The value of ChildContent is received from the parent component and rendered inside the Bootstrap panel's panel-body.

Components/ChildComponent.razor:Components/ChildComponent.razor:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

注意

RenderFragment コンテンツを受け取るプロパティは、規則によって ChildContent という名前にする必要があります。The property receiving the RenderFragment content must be named ChildContent by convention.

サンプル アプリの ParentComponent では、コンテンツを <ChildComponent> タグ内に配置することによって、ChildComponent をレンダリングするためのコンテンツを提供できます。The ParentComponent in the sample app can provide content for rendering the ChildComponent by placing the content inside the <ChildComponent> tags.

Pages/ParentComponent.razor:Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClickCallback="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

属性スプラッティングと任意のパラメーターAttribute splatting and arbitrary parameters

コンポーネントでは、コンポーネントの宣言されたパラメーターに加えて、追加の属性をキャプチャしてレンダリングできます。Components can capture and render additional attributes in addition to the component's declared parameters. 追加の属性は、ディクショナリにキャプチャし、@attributes Razor ディレクティブを使用して、コンポーネントがレンダリングされるときに、要素にスプラッティングできます。Additional attributes can be captured in a dictionary and then splatted onto an element when the component is rendered using the @attributes Razor directive. このシナリオは、さまざまなカスタマイズをサポートするマークアップ要素を生成するコンポーネントを定義する場合に便利です。This scenario is useful when defining a component that produces a markup element that supports a variety of customizations. たとえば、多くのパラメーターをサポートする <input> に対して、属性を個別に定義するのは面倒な場合があります。For example, it can be tedious to define attributes separately for an <input> that supports many parameters.

次の例で、最初の <input> 要素 (id="useIndividualParams") では、個々のコンポーネント パラメーターを使用していますが、2 番目の <input> 要素 (id="useAttributesDict") では、属性スプラッティングを使用しています。In the following example, the first <input> element (id="useIndividualParams") uses individual component parameters, while the second <input> element (id="useAttributesDict") uses attribute splatting:

<input id="useIndividualParams"
       maxlength="@Maxlength"
       placeholder="@Placeholder"
       required="@Required"
       size="@Size" />

<input id="useAttributesDict"
       @attributes="InputAttributes" />

@code {
    [Parameter]
    public string Maxlength { get; set; } = "10";

    [Parameter]
    public string Placeholder { get; set; } = "Input placeholder text";

    [Parameter]
    public string Required { get; set; } = "required";

    [Parameter]
    public string Size { get; set; } = "50";

    [Parameter]
    public Dictionary<string, object> InputAttributes { get; set; } =
        new Dictionary<string, object>()
        {
            { "maxlength", "10" },
            { "placeholder", "Input placeholder text" },
            { "required", "required" },
            { "size", "50" }
        };
}

パラメーターの型は、文字列キーで IEnumerable<KeyValuePair<string, object>> を実装する必要があります。The type of the parameter must implement IEnumerable<KeyValuePair<string, object>> with string keys. このシナリオでは IReadOnlyDictionary<string, object> を使用することもできます。Using IReadOnlyDictionary<string, object> is also an option in this scenario.

両方の方法を使用してレンダリングされる <input> 要素は同じです。The rendered <input> elements using both approaches is identical:

<input id="useIndividualParams"
       maxlength="10"
       placeholder="Input placeholder text"
       required="required"
       size="50">

<input id="useAttributesDict"
       maxlength="10"
       placeholder="Input placeholder text"
       required="required"
       size="50">

任意の属性を受け入れるには、CaptureUnmatchedValues プロパティを true に設定した [Parameter] 属性を使用して、コンポーネント パラメーターを定義します。To accept arbitrary attributes, define a component parameter using the [Parameter] attribute with the CaptureUnmatchedValues property set to true:

@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> InputAttributes { get; set; }
}

[Parameter]CaptureUnmatchedValues プロパティにより、パラメーターを他のパラメーターと一致しないすべての属性と一致させることができます。The CaptureUnmatchedValues property on [Parameter] allows the parameter to match all attributes that don't match any other parameter. 1 つのコンポーネントで、CaptureUnmatchedValues を持つパラメーターは 1 つだけ定義できます。A component can only define a single parameter with CaptureUnmatchedValues. CaptureUnmatchedValues で使用されるプロパティの型は、文字列キーを使用して Dictionary<string, object> から割り当て可能である必要があります。The property type used with CaptureUnmatchedValues must be assignable from Dictionary<string, object> with string keys. このシナリオでは、IEnumerable<KeyValuePair<string, object>> または IReadOnlyDictionary<string, object> も使用できます。IEnumerable<KeyValuePair<string, object>> or IReadOnlyDictionary<string, object> are also options in this scenario.

要素属性の位置を基準とした @attributes の位置は重要です。The position of @attributes relative to the position of element attributes is important. @attributes が要素にスプラッティングされると、属性は右から左 (最後から最初) に処理されます。When @attributes are splatted on the element, the attributes are processed from right to left (last to first). Child コンポーネントを使用する次のコンポーネントの例を考えます。Consider the following example of a component that consumes a Child component:

ParentComponent.razor:ParentComponent.razor:

<ChildComponent extra="10" />

ChildComponent.razor:ChildComponent.razor:

<div @attributes="AdditionalAttributes" extra="5" />

[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; }

Child コンポーネントの extra 属性が @attributes の右側に設定されています。The Child component's extra attribute is set to the right of @attributes. 属性は右から左 (最後から最初) に処理されるため、追加の属性によって渡された場合に、Parent コンポーネントのレンダリングされる <div> に、extra="5" が含まれます。The Parent component's rendered <div> contains extra="5" when passed through the additional attribute because the attributes are processed right to left (last to first):

<div extra="5" />

次の例では、Child コンポーネントの <div> で、extra@attributes の順序が逆になります。In the following example, the order of extra and @attributes is reversed in the Child component's <div>:

ParentComponent.razor:ParentComponent.razor:

<ChildComponent extra="10" />

ChildComponent.razor:ChildComponent.razor:

<div extra="5" @attributes="AdditionalAttributes" />

[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; }

追加の属性によって渡された場合に、Parent コンポーネント内のレンダリングされる <div> には、extra="10" が含まれます。The rendered <div> in the Parent component contains extra="10" when passed through the additional attribute:

<div extra="10" />

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

コンポーネント参照によって、コンポーネント インスタンスを参照する方法が得られるため、そのインスタンスに ShowReset などのコマンドを発行できます。Component references provide a way to reference a component instance so that you can issue commands to that instance, such as Show or Reset. コンポーネント参照をキャプチャするには:To capture a component reference:

  • 子コンポーネントに @ref 属性を追加します。Add an @ref attribute to the child component.
  • 子コンポーネントと同じ型のフィールドを定義します。Define a field with the same type as the child component.
<MyLoginDialog @ref="_loginDialog" ... />

@code {
    private MyLoginDialog _loginDialog;

    private void OnSomething()
    {
        _loginDialog.Show();
    }
}

コンポーネントがレンダリングされると、_loginDialog フィールドに MyLoginDialog 子コンポーネント インスタンスが設定されます。When the component is rendered, the _loginDialog field is populated with the MyLoginDialog child component instance. これにより、コンポーネント インスタンスに対し、.NET メソッドを呼び出すことができます。You can then invoke .NET methods on the component instance.

重要

_loginDialog 変数は、コンポーネントがレンダリングされた後にのみ設定され、その出力には MyLoginDialog 要素が含まれます。The _loginDialog variable is only populated after the component is rendered and its output includes the MyLoginDialog element. この時点まで、何も参照できません。Until that point, there's nothing to reference. コンポーネントのレンダリングが完了した後にコンポーネント参照を操作するには、OnAfterRenderAsync メソッドまたは OnAfterRender メソッドを使用します。To manipulate components references after the component has finished rendering, use the OnAfterRenderAsync or OnAfterRender methods.

コンポーネント参照のキャプチャでは、要素参照のキャプチャと類似の構文を使用しますが、それは JavaScript 相互運用機能ではありません。While capturing component references use a similar syntax to capturing element references, it isn't a JavaScript interop feature. コンポーネント参照は、JavaScript コードに渡されません — それらは .NET コードでのみ使用されます。Component references aren't passed to JavaScript code—they're only used in .NET code.

注意

子コンポーネントの状態を変えるためにコンポーネント参照を使用しないでください。Do not use component references to mutate the state of child components. 代わりに、通常の宣言型パラメーターを使用して、子コンポーネントにデータを渡します。Instead, use normal declarative parameters to pass data to child components. 通常の宣言型パラメーターを使用すると、子コンポーネントが正しいタイミングで自動的にレンダリングされます。Use of normal declarative parameters result in child components that rerender at the correct times automatically.

状態を更新するために外部でコンポーネント メソッドを呼び出すInvoke component methods externally to update state

Blazor では、SynchronizationContext を使用して、1 つの論理スレッドを強制的に実行します。 uses a SynchronizationContext to enforce a single logical thread of execution. コンポーネントの ライフサイクル メソッドと Blazor によって発生するイベント コールバックは、この SynchronizationContext で実行されます。A component's lifecycle methods and any event callbacks that are raised by Blazor are executed on this SynchronizationContext. タイマーやその他の通知などの外部のイベントに基づいてコンポーネントを更新する必要がある場合は、InvokeAsync メソッドを使用します。これにより、Blazor の SynchronizationContext にディスパッチされます。In the event a component must be updated based on an external event, such as a timer or other notifications, use the InvokeAsync method, which will dispatch to Blazor's SynchronizationContext.

たとえば、リッスンしているコンポーネントに、更新状態を通知できる通知サービス を考えてみます。For example, consider a notifier service that can notify any listening component of the updated state:

public class NotifierService
{
    // Can be called from anywhere
    public async Task Update(string key, int value)
    {
        if (Notify != null)
        {
            await Notify.Invoke(key, value);
        }
    }

    public event Func<string, int, Task> Notify;
}

NotifierService をシングルトンとして登録します。Register the NotifierService as a singletion:

  • Blazor WebAssembly で、Program.Main にサービスを登録します。In Blazor WebAssembly, register the service in Program.Main:

    builder.Services.AddSingleton<NotifierService>();
    
  • Blazor サーバーで、Startup.ConfigureServices にサービスを登録します。In Blazor Server, register the service in Startup.ConfigureServices:

    services.AddSingleton<NotifierService>();
    

NotifierService を使用して、コンポーネントを更新します。Use the NotifierService to update a component:

@page "/"
@inject NotifierService Notifier
@implements IDisposable

<p>Last update: @_lastNotification.key = @_lastNotification.value</p>

@code {
    private (string key, int value) _lastNotification;

    protected override void OnInitialized()
    {
        Notifier.Notify += OnNotify;
    }

    public async Task OnNotify(string key, int value)
    {
        await InvokeAsync(() =>
        {
            _lastNotification = (key, value);
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        Notifier.Notify -= OnNotify;
    }
}

前の例では、NotifierService が Blazor の SynchronizationContext の外部で、コンポーネントの OnNotify メソッドを呼び出します。In the preceding example, NotifierService invokes the component's OnNotify method outside of Blazor's SynchronizationContext. InvokeAsync を使用して、正しいコンテキストに切り替え、レンダリングをキューに登録します。InvokeAsync is used to switch to the correct context and queue a render.

@ キーを使用して要素とコンポーネントの保存を制御するUse @key to control the preservation of elements and components

要素またはコンポーネントのリストをレンダリングし、その後に要素またはコンポーネントが変更された場合、Blazor の比較アルゴリズムでは、前のどの要素やコンポーネントを保持できるか、およびモデル オブジェクトをそれらにどのようにマップするかを決定する必要があります。When rendering a list of elements or components and the elements or components subsequently change, Blazor's diffing algorithm must decide which of the previous elements or components can be retained and how model objects should map to them. 通常、このプロセスは自動で、無視できますが、プロセスの制御が必要になる場合があります。Normally, this process is automatic and can be ignored, but there are cases where you may want to control the process.

次に例を示します。Consider the following example:

@foreach (var person in People)
{
    <DetailsEditor Details="@person.Details" />
}

@code {
    [Parameter]
    public IEnumerable<Person> People { get; set; }
}

People コレクションのコンテンツは、挿入、削除、または順序変更されたエントリによって変更される可能性があります。The contents of the People collection may change with inserted, deleted, or re-ordered entries. コンポーネントのレンダリング時に、<DetailsEditor> コンポーネントが変更され、異なる Details パラメーター値を受け取ることがあります。When the component rerenders, the <DetailsEditor> component may change to receive different Details parameter values. これにより、予期したものよりも複雑な再レンダリングが発生する可能性があります。This may cause more complex rerendering than expected. 場合によっては、再レンダリングによって、要素のフォーカスの喪失などの表示動作の違いが発生する可能性があります。In some cases, rerendering can lead to visible behavior differences, such as lost element focus.

マッピング プロセスは、@key ディレクティブ属性を使用して制御できます。The mapping process can be controlled with the @key directive attribute. @key により、比較アルゴリズムで、キーの値に基づいて要素やコンポーネントが確実に保持されます。@key causes the diffing algorithm to guarantee preservation of elements or components based on the key's value:

@foreach (var person in People)
{
    <DetailsEditor @key="person" Details="@person.Details" />
}

@code {
    [Parameter]
    public IEnumerable<Person> People { get; set; }
}

People コレクションが変更されても、比較アルゴリズムによって、<DetailsEditor> インスタンスと person インスタンス間の関連付けが保持されます。When the People collection changes, the diffing algorithm retains the association between <DetailsEditor> instances and person instances:

  • PersonPeople リストから削除された場合、対応する <DetailsEditor> インスタンスだけが UI から削除されます。If a Person is deleted from the People list, only the corresponding <DetailsEditor> instance is removed from the UI. 他のインスタンスは変更されません。Other instances are left unchanged.
  • リスト内の特定の位置に Person が挿入されると、その対応する位置に、1 つの新しい <DetailsEditor> インスタンスが挿入されます。If a Person is inserted at some position in the list, one new <DetailsEditor> instance is inserted at that corresponding position. 他のインスタンスは変更されません。Other instances are left unchanged.
  • Person エントリの順序が変更された場合、対応する <DetailsEditor> インスタンスは UI で保持され、順序が変更されます。If Person entries are re-ordered, the corresponding <DetailsEditor> instances are preserved and re-ordered in the UI.

シナリオによっては、@key を使用すると、レンダリングの複雑さが最小限に抑えられ、フォーカス位置など、DOM 変更のステートフルな部分の潜在的な問題を回避できます。In some scenarios, use of @key minimizes the complexity of rerendering and avoids potential issues with stateful parts of the DOM changing, such as focus position.

重要

キーは、各コンテナー要素やコンポーネントに対してローカルです。Keys are local to each container element or component. キーはドキュメント全体でグローバルに比較されません。Keys aren't compared globally across the document.

@ キーを使用する場面When to use @key

一般に、リストがレンダリングされ (たとえば、@foreach ブロックで)、@key を定義するための適切な値が存在する場合は常に、@key を使用することは意味があります。Typically, it makes sense to use @key whenever a list is rendered (for example, in a @foreach block) and a suitable value exists to define the @key.

また、@key を使用して、オブジェクトが変更されたときに Blazor が要素やコンポーネントのサブツリーを保持しないようにすることもできます。You can also use @key to prevent Blazor from preserving an element or component subtree when an object changes:

<div @key="currentPerson">
    ... content that depends on currentPerson ...
</div>

@currentPerson が変更された場合、@key 属性ディレクティブによって、Blazor に、<div> とその子孫全体を破棄させ、新しい要素とコンポーネントで UI 内のサブツリーをリビルドさせます。If @currentPerson changes, the @key attribute directive forces Blazor to discard the entire <div> and its descendants and rebuild the subtree within the UI with new elements and components. これは、@currentPerson が変更されたときに、UI の状態が確実に保持されないようにする必要がある場合に役立つ可能性があります。This can be useful if you need to guarantee that no UI state is preserved when @currentPerson changes.

@ キーを使用しない場面When not to use @key

@key で比較すると、パフォーマンスが低下します。There's a performance cost when diffing with @key. パフォーマンスの低下は大きくありませんが、要素やコンポーネントの保存規則を制御することによって、アプリにメリットがある場合にのみ @key を指定してください。The performance cost isn't large, but only specify @key if controlling the element or component preservation rules benefit the app.

@key を使用しない場合でも、Blazor では可能な限り、子要素とコンポーネント インスタンスが保持されます。Even if @key isn't used, Blazor preserves child element and component instances as much as possible. @key を使用する唯一の利点は、マッピングを選択する比較アルゴリズムではなく、保持されているコンポーネント インスタンスにモデル インスタンスをマップする方法を制御することです。The only advantage to using @key is control over how model instances are mapped to the preserved component instances, instead of the diffing algorithm selecting the mapping.

@ キーに使用する値What values to use for @key

一般に、@key には、次のいずれかの種類の値を指定するのが適切です。Generally, it makes sense to supply one of the following kinds of value for @key:

  • モデル オブジェクトインスタンス (たとえば、前の例のように、Person インスタンス)。Model object instances (for example, a Person instance as in the earlier example). これにより、オブジェクト参照の等価性に基づいて保持されます。This ensures preservation based on object reference equality.
  • 一意の識別子 (たとえば、int 型、string 型、Guid 型の主キー値)。Unique identifiers (for example, primary key values of type int, string, or Guid).

@key に使用される値は競合しないようにしてください。Ensure that values used for @key don't clash. 同じ親要素内で競合する値が検出された場合、Blazor では、古い要素やコンポーネントを新しい要素やコンポーネントに確定的にマップできないため、例外がスローされます。If clashing values are detected within the same parent element, Blazor throws an exception because it can't deterministically map old elements or components to new elements or components. 個別の値 (オブジェクト インスタンスや主キー値など) のみを使用してください。Only use distinct values, such as object instances or primary key values.

部分クラスのサポートPartial class support

Razor コンポーネントは、部分クラスとして生成されます。Razor components are generated as partial classes. Razor コンポーネントは、次のいずれかの方法を使用して作成します。Razor components are authored using either of the following approaches:

  • C# コードは、1 つのファイルに HTML マークアップと Razor コードを含む @code ブロックで定義します。C# code is defined in an @code block with HTML markup and Razor code in a single file. Blazor テンプレートでは、この方法を使用して Razor コンポーネントを定義します。 templates define their Razor components using this approach.
  • C# コードは、部分クラスとして定義されている分離コード ファイルに配置されます。C# code is placed in a code-behind file defined as a partial class.

次の例は、Blazor テンプレートから生成されたアプリ内の @code ブロックを含む既定の Counter コンポーネントを示しています。The following example shows the default Counter component with an @code block in an app generated from a Blazor template. HTML マークアップ、Razor コード、C# コードは、同じファイル内にあります。HTML markup, Razor code, and C# code are in the same file:

Counter.razor:Counter.razor:

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

    void IncrementCount()
    {
        _currentCount++;
    }
}

Counter コンポーネントは、部分クラスを含む分離コード ファイルを使用して作成することもできます。The Counter component can also be created using a code-behind file with a partial class:

Counter.razor:Counter.razor:

@page "/counter"

<h1>Counter</h1>

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

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

Counter.razor.cs:Counter.razor.cs:

namespace BlazorApp.Pages
{
    public partial class Counter
    {
        private int _currentCount = 0;

        void IncrementCount()
        {
            _currentCount++;
        }
    }
}

必要に応じて、部分クラスファイルに必要な名前空間を追加します。Add any required namespaces to the partial class file as needed. Razor コンポーネントで使用される一般的な名前空間には次のものが含まれます。Typical namespaces used by Razor components include:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;

基本クラスの指定Specify a base class

@inherits ディレクティブを使用して、コンポーネントの基本クラスを指定できます。The @inherits directive can be used to specify a base class for a component. 次の例は、コンポーネントが基本クラス BlazorRocksBase を継承して、コンポーネントのプロパティとメソッドを提供する方法を示しています。The following example shows how a component can inherit a base class, BlazorRocksBase, to provide the component's properties and methods. 基本クラスは ComponentBase から派生する必要があります。The base class should derive from ComponentBase.

Pages/BlazorRocks.razor:Pages/BlazorRocks.razor:

@page "/BlazorRocks"
@inherits BlazorRocksBase

<h1>@BlazorRocksText</h1>

BlazorRocksBase.cs:BlazorRocksBase.cs:

using Microsoft.AspNetCore.Components;

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

属性の指定Specify an attribute

属性は、@attribute ディレクティブを使用して Razor コンポーネントに指定できます。Attributes can be specified in Razor components with the @attribute directive. 次の例では、[Authorize] 属性をコンポーネント クラスに適用しています。The following example applies the [Authorize] attribute to the component class:

@page "/"
@attribute [Authorize]

コンポーネントのインポートImport components

Razor で作成されるコンポーネントの名前空間は、次に基づきます (優先順で)。The namespace of a component authored with Razor is based on (in priority order):

  • Razor ファイル ( .razor) マークアップ内の @namespace の指定 (@namespace BlazorSample.MyNamespace)。@namespace designation in Razor file (.razor) markup (@namespace BlazorSample.MyNamespace).
  • プロジェクト ファイル内のプロジェクトの RootNamespace (<RootNamespace>BlazorSample</RootNamespace>)。The project's RootNamespace in the project file (<RootNamespace>BlazorSample</RootNamespace>).
  • プロジェクト ファイルのファイル名 ( .csproj) から取得されたプロジェクト名、およびプロジェクト ルートからコンポーネントへのパス。The project name, taken from the project file's file name (.csproj), and the path from the project root to the component. たとえば、フレームワークでは {PROJECT ROOT}/Pages/Index.razor (BlazorSample.csproj) が名前空間 BlazorSample.Pages に解決されます。For example, the framework resolves {PROJECT ROOT}/Pages/Index.razor (BlazorSample.csproj) to the namespace BlazorSample.Pages. コンポーネントは C# の名前のバインド規則に従います。Components follow C# name binding rules. この例の Index コンポーネントの場合、スコープ内のコンポーネントは、次のすべてのコンポーネントです。For the Index component in this example, the components in scope are all of the components:
    • 同じ Pages フォルダー内。In the same folder, Pages.
    • 別の名前空間を明示的に指定しない、プロジェクトのルート内のコンポーネント。The components in the project's root that don't explicitly specify a different namespace.

別の名前空間に定義されているコンポーネントは、Razor の @using ディレクティブを使用してスコープ内に取り込みます。Components defined in a different namespace are brought into scope using Razor's @using directive.

別のコンポーネントの NavMenu.razorBlazorSample/Shared/ フォルダーに存在する場合は、次の @using ステートメントを使用して、そのコンポーネントを Index.razor で使用できます。If another component, NavMenu.razor, exists in the BlazorSample/Shared/ folder, the component can be used in Index.razor with the following @using statement:

@using BlazorSample.Shared

This is the Index page.

<NavMenu></NavMenu>

コンポーネントは、完全修飾名を使用して参照することもできます。この場合、@using ディレクティブは必要ありません。Components can also be referenced using their fully qualified names, which doesn't require the @using directive:

This is the Index page.

<BlazorSample.Shared.NavMenu></BlazorSample.Shared.NavMenu>

注意

global:: 修飾はサポートされていません。The global:: qualification isn't supported.

別名が付けられた using ステートメント (@using Foo = Bar など) によるコンポーネントのインポートはサポートされていません。Importing components with aliased using statements (for example, @using Foo = Bar) isn't supported.

部分修飾名はサポートされていません。Partially qualified names aren't supported. たとえば、<Shared.NavMenu></Shared.NavMenu> による @using BlazorSample の追加と NavMenu.razor の参照はサポートされていません。For example, adding @using BlazorSample and referencing NavMenu.razor with <Shared.NavMenu></Shared.NavMenu> isn't supported.

条件付き HTML 要素属性Conditional HTML element attributes

HTML 要素属性は、.NET 値に基づいて条件付きでレンダリングされます。HTML element attributes are conditionally rendered based on the .NET value. 値が false または null の場合、属性はレンダリングされません。If the value is false or null, the attribute isn't rendered. 値が true の場合、属性が最小化されてレンダリングされます。If the value is true, the attribute is rendered minimized.

次の例では、IsCompleted によって checked が要素のマークアップにレンダリングされるかどうかを決定します。In the following example, IsCompleted determines if checked is rendered in the element's markup:

<input type="checkbox" checked="@IsCompleted" />

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

IsCompletedtrue の場合、このチェック ボックスは次のようにレンダリングされます。If IsCompleted is true, the check box is rendered as:

<input type="checkbox" checked />

IsCompletedfalse の場合、このチェック ボックスは次のようにレンダリングされます。If IsCompleted is false, the check box is rendered as:

<input type="checkbox" />

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

警告

.NET 型が bool の場合、aria-pressed などの一部の HTML 属性が正しく機能しません。Some HTML attributes, such as aria-pressed, don't function properly when the .NET type is a bool. そのような場合は、bool ではなく string 型を使用します。In those cases, use a string type instead of a bool.

生 HTMLRaw HTML

通常、文字列は DOM テキスト ノードを使用してレンダリングされます。つまり、それらに含まれている可能性のあるすべてのマークアップが無視され、リテラル テキストとして扱われます。Strings are normally rendered using DOM text nodes, which means that any markup they may contain is ignored and treated as literal text. 生 HTML をレンダリングするには、HTML コンテンツを MarkupString 値にラップします。To render raw HTML, wrap the HTML content in a MarkupString value. 値は HTML または SVG として解析され、DOM に挿入されます。The value is parsed as HTML or SVG and inserted into the DOM.

警告

信頼されていないソースから構築された生 HTML をレンダリングすることは、セキュリティ リスクであるため、避ける必要があります。Rendering raw HTML constructed from any untrusted source is a security risk and should be avoided!

次の例では、MarkupString 型を使用して、コンポーネントのレンダリングされた出力に静的 HTML コンテンツのブロックを追加しています。The following example shows using the MarkupString type to add a block of static HTML content to the rendered output of a component:

@((MarkupString)_myMarkup)

@code {
    private string _myMarkup = 
        "<p class='markup'>This is a <em>markup string</em>.</p>";
}

値とパラメーターのカスケードCascading values and parameters

一部のシナリオでは、特に複数のコンポーネント レイヤーがある場合に、コンポーネント パラメーターを使用して、先祖コンポーネントから子孫コンポーネントにデータをフローすることが不便な場合があります。In some scenarios, it's inconvenient to flow data from an ancestor component to a descendent component using component parameters, especially when there are several component layers. 値とパラメーターのカスケードによって、先祖コンポーネントがそのすべての子孫コンポーネントに値を提供するための便利な方法を用意することで、この問題が解決されます。Cascading values and parameters solve this problem by providing a convenient way for an ancestor component to provide a value to all of its descendent components. 値とパラメーターのカスケードによって、コンポーネントで調整する方法も得られます。Cascading values and parameters also provide an approach for components to coordinate.

テーマの例Theme example

次のサンプル アプリの例では、ThemeInfo クラスで、コンポーネント階層の下位に伝達されるテーマ情報を指定して、アプリの特定の部分にあるすべてのボタンが同じスタイルを共有するようにしています。In the following example from the sample app, the ThemeInfo class specifies the theme information to flow down the component hierarchy so that all of the buttons within a given part of the app share the same style.

UIThemeClasses/ThemeInfo.cs:UIThemeClasses/ThemeInfo.cs:

public class ThemeInfo
{
    public string ButtonClass { get; set; }
}

先祖コンポーネントでは、Cascading Value コンポーネントを使用してカスケード値を指定できます。An ancestor component can provide a cascading value using the Cascading Value component. CascadingValue コンポーネントは、コンポーネント階層のサブツリーをラップし、そのサブツリー内のすべてのコンポーネントに単一の値を指定します。The CascadingValue component wraps a subtree of the component hierarchy and supplies a single value to all components within that subtree.

たとえば、サンプル アプリでは、アプリのレイアウトの 1 つに、@Body プロパティのレイアウト本体を構成するすべてのコンポーネントのカスケード パラメーターとして、テーマ情報 (ThemeInfo) を指定しています。For example, the sample app specifies theme information (ThemeInfo) in one of the app's layouts as a cascading parameter for all components that make up the layout body of the @Body property. ButtonClass には、レイアウト コンポーネント内の btn-success の値が割り当てられます。ButtonClass is assigned a value of btn-success in the layout component. すべての子孫コンポーネントで、ThemeInfo カスケード オブジェクトからこのプロパティを使用できます。Any descendent component can consume this property through the ThemeInfo cascading object.

CascadingValuesParametersLayout コンポーネント:CascadingValuesParametersLayout component:

@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="container-fluid">
    <div class="row">
        <div class="col-sm-3">
            <NavMenu />
        </div>
        <div class="col-sm-9">
            <CascadingValue Value="_theme">
                <div class="content px-4">
                    @Body
                </div>
            </CascadingValue>
        </div>
    </div>
</div>

@code {
    private ThemeInfo _theme = new ThemeInfo { ButtonClass = "btn-success" };
}

カスケード値を使用するには、コンポーネントで [CascadingParameter] 属性を使用してカスケード パラメーターを宣言します。To make use of cascading values, components declare cascading parameters using the [CascadingParameter] attribute. カスケード値は、型によってカスケード パラメーターにバインドされます。Cascading values are bound to cascading parameters by type.

サンプル アプリでは、CascadingValuesParametersTheme コンポーネントによって ThemeInfo カスケード値をカスケード パラメーターにバインドしています。In the sample app, the CascadingValuesParametersTheme component binds the ThemeInfo cascading value to a cascading parameter. パラメーターは、コンポーネントによって表示されるボタンの 1 つに CSS クラスを設定するために使用されます。The parameter is used to set the CSS class for one of the buttons displayed by the component.

CascadingValuesParametersTheme コンポーネント:CascadingValuesParametersTheme component:

@page "/cascadingvaluesparameterstheme"
@layout CascadingValuesParametersLayout
@using BlazorSample.UIThemeClasses

<h1>Cascading Values & Parameters</h1>

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

<p>
    <button class="btn" @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button class="btn @ThemeInfo.ButtonClass" @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int _currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo ThemeInfo { get; set; }

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

同じサブツリー内で同じ型の複数の値をカスケードするには、各 CascadingValue コンポーネントとその対応する CascadingParameter に一意の Name 文字列を指定します。To cascade multiple values of the same type within the same subtree, provide a unique Name string to each CascadingValue component and its corresponding CascadingParameter. 次の例では、2 つの CascadingValue コンポーネントで、名前によって MyCascadingType の異なるインスタンスをカスケードしています。In the following example, two CascadingValue components cascade different instances of MyCascadingType by name:

<CascadingValue Value=@_parentCascadeParameter1 Name="CascadeParam1">
    <CascadingValue Value=@ParentCascadeParameter2 Name="CascadeParam2">
        ...
    </CascadingValue>
</CascadingValue>

@code {
    private MyCascadingType _parentCascadeParameter1;

    [Parameter]
    public MyCascadingType ParentCascadeParameter2 { get; set; }

    ...
}

子孫コンポーネントでは、カスケードされたパラメーターは、それらの値を、名前によって、先祖コンポーネント内の対応するカスケードされた値から受け取ります。In a descendant component, the cascaded parameters receive their values from the corresponding cascaded values in the ancestor component by name:

...

@code {
    [CascadingParameter(Name = "CascadeParam1")]
    protected MyCascadingType ChildCascadeParameter1 { get; set; }
    
    [CascadingParameter(Name = "CascadeParam2")]
    protected MyCascadingType ChildCascadeParameter2 { get; set; }
}

TabSet の例TabSet example

パラメーターのカスケードによって、コンポーネント階層全体でコンポーネントを連携させることもできます。Cascading parameters also enable components to collaborate across the component hierarchy. たとえば、サンプル アプリの次の TabSet の例を考えてみましょう。For example, consider the following TabSet example in the sample app.

このサンプル アプリには、タブに実装されている ITab インターフェイスがあります。The sample app has an ITab interface that tabs implement:

using Microsoft.AspNetCore.Components;

namespace BlazorSample.UIInterfaces
{
    public interface ITab
    {
        RenderFragment ChildContent { get; }
    }
}

CascadingValuesParametersTabSet コンポーネントでは、いくつかの Tab コンポーネントを含む TabSet コンポーネントを使用します。The CascadingValuesParametersTabSet component uses the TabSet component, which contains several Tab components:

<TabSet>
    <Tab Title="First tab">
        <h4>Greetings from the first tab!</h4>

        <label>
            <input type="checkbox" @bind="showThirdTab" />
            Toggle third tab
        </label>
    </Tab>
    <Tab Title="Second tab">
        <h4>The second tab says Hello World!</h4>
    </Tab>

    @if (showThirdTab)
    {
        <Tab Title="Third tab">
            <h4>Welcome to the disappearing third tab!</h4>
            <p>Toggle this tab from the first tab.</p>
        </Tab>
    }
</TabSet>

Tab コンポーネントは、パラメーターとして TabSet に明示的に渡されません。The child Tab components aren't explicitly passed as parameters to the TabSet. 代わりに、子 Tab コンポーネントは、TabSet の子コンテンツに含まれます。Instead, the child Tab components are part of the child content of the TabSet. ただし、TabSet は、ヘッダーとアクティブなタブをレンダリングできるように、各 Tab コンポーネントについて認識している必要があります。追加のコードを必要とせずにこの調整を可能にするために、TabSet コンポーネントでは、それ自体をカスケード値として指定し、その後に子孫 Tab コンポーネントによって取得できるようにします。However, the TabSet still needs to know about each Tab component so that it can render the headers and the active tab. To enable this coordination without requiring additional code, the TabSet component can provide itself as a cascading value that is then picked up by the descendent Tab components.

TabSet コンポーネント:TabSet component:

@using BlazorSample.UIInterfaces

<!-- Display the tab headers -->
<CascadingValue Value=this>
    <ul class="nav nav-tabs">
        @ChildContent
    </ul>
</CascadingValue>

<!-- Display body for only the active tab -->
<div class="nav-tabs-body p-4">
    @ActiveTab?.ChildContent
</div>

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

    public ITab ActiveTab { get; private set; }

    public void AddTab(ITab tab)
    {
        if (ActiveTab == null)
        {
            SetActivateTab(tab);
        }
    }

    public void RemoveTab(ITab tab)
    {
        if (ActiveTab == tab)
        {
            SetActivateTab(null);
        }
    }

    public void SetActivateTab(ITab tab)
    {
        if (ActiveTab != tab)
        {
            ActiveTab = tab;
            StateHasChanged();
        }
    }
}

子孫の Tab コンポーネントでは、含まれている TabSet をカスケード パラメーターとしてキャプチャするため、Tab コンポーネントはそれ自体を TabSet に追加し、どのタブをアクティブにするかを調整します。The descendent Tab components capture the containing TabSet as a cascading parameter, so the Tab components add themselves to the TabSet and coordinate on which tab is active.

Tab コンポーネント:Tab component:

@using BlazorSample.UIInterfaces
@implements ITab

<li>
    <a @onclick="Activate" class="nav-link @TitleCssClass" role="button">
        @Title
    </a>
</li>

@code {
    [CascadingParameter]
    public TabSet ContainerTabSet { get; set; }

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

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

    private string TitleCssClass => ContainerTabSet.ActiveTab == this ? "active" : null;

    protected override void OnInitialized()
    {
        ContainerTabSet.AddTab(this);
    }

    private void Activate()
    {
        ContainerTabSet.SetActivateTab(this);
    }
}

Razor テンプレートRazor templates

レンダリング フラグメントは、Razor テンプレート構文を使用して定義できます。Render fragments can be defined using Razor template syntax. Razor テンプレートは、UI スニペットを定義する 1 つの方法であり、次の形式を想定しています。Razor templates are a way to define a UI snippet and assume the following format:

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

次の例では、RenderFragmentRenderFragment<T> の値を指定し、コンポーネント内にテンプレートを直接レンダリングする方法を示しています。The following example illustrates how to specify RenderFragment and RenderFragment<T> values and render templates directly in a component. レンダリング フラグメントは、引数としてテンプレート コンポーネントに渡すこともできます。Render fragments can also be passed as arguments to templated components.

@_timeTemplate

@_petTemplate(new Pet { Name = "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; }
    }
}

前のコードのレンダリングされた結果:Rendered output of the preceding code:

<p>The time is 10/04/2018 01:26:52.</p>

<p>Pet: Rex</p>

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

Blazor は HTML をレンダリングするため、スケーラブル ベクター グラフィックス (SVG) イメージ ( .svg) などのブラウザーでサポートされているイメージは、<img> タグを介してサポートされます。Since Blazor renders HTML, browser-supported images, including Scalable Vector Graphics (SVG) images (.svg), are supported via the <img> tag:

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

同様に、SVG イメージは、スタイルシート ファイル ( .css) の CSS 規則でサポートされています。Similarly, SVG images are supported in the CSS rules of a stylesheet file (.css):

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

ただし、インライン SVG マークアップは、すべてのシナリオでサポートされているわけではありません。However, inline SVG markup isn't supported in all scenarios. <svg> タグをコンポーネント ファイル ( .razor) に直接配置した場合、基本的なイメージ レンダリングはサポートされますが、多くの高度なシナリオはまだサポートされていません。If you place an <svg> tag directly into a component file (.razor), basic image rendering is supported but many advanced scenarios aren't yet supported. たとえば、<use> タグは現在考慮されないため、一部の SVG タグで @bind を使用できません。For example, <use> tags aren't currently respected, and @bind can't be used with some SVG tags. 将来のリリースで、これらの制限に対処する予定です。We expect to address these limitations in a future release.

その他の技術情報Additional resources