ASP.NET Core Razor コンポーネントを作成して使用するCreate and use ASP.NET Core Razor components

Luke LathamおよびDaniel 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. コンポーネントには、HTML マークアップと、データを挿入したり UI イベントに応答したりするために必要な処理ロジックが含まれています。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

コンポーネントは、と HTML マークアップの C#組み合わせを使用して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は有効で、 MyCoolComponentは無効です。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:

  • font-styleの CSS プロパティ値に _headingFontStyle します。_headingFontStyle to the CSS property value for font-style.
  • <h1> 要素の内容に _headingText します。_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 ページを生成するコンポーネントは、通常、[ページ] フォルダーにあります。Components that produce webpages usually reside in the Pages folder. ページ以外のコンポーネントは、多くの場合、プロジェクトに追加された共有フォルダーまたはカスタムフォルダーに配置されます。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. アプリのルート名前空間が BlazorAppCounter コンポーネントがPagesフォルダーに存在する場合は、次のようになります。If the app's root namespace is BlazorApp and the Counter component resides in the Pages folder:

  • Counter コンポーネントの名前空間が BlazorApp.PagesThe 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場合に、コンポーネントフォルダー内のコンポーネントを使用可能にします。For example, the following namespace makes components in a Components folder available when the app's root namespace is BlazorApp:

@using BlazorApp.Components

コンポーネントを Razor Pages と MVC アプリに統合するIntegrate components into Razor Pages and MVC apps

Razor コンポーネントは Razor Pages と MVC アプリに統合できます。Razor components can be integrated into Razor Pages and MVC apps. ページまたはビューが表示されると、コンポーネントを同時に prerendered することができます。When the page or view is rendered, components can be prerendered at the same time.

Razor コンポーネントをホストする Razor Pages または MVC アプリを準備するには、Blazor ホスティングモデルの ASP.NET Core の記事の「 razor コンポーネントを Razor Pages および mvc アプリに統合する」セクションのガイダンスに従ってください。To prepare a Razor Pages or MVC app to host Razor components, follow the guidance in the Integrate Razor components into Razor Pages and MVC apps section of the Blazor ホスティングモデルの ASP.NET Core article.

カスタムフォルダーを使用してアプリのコンポーネントを保持する場合は、フォルダーを表す名前空間をページ/ビューまたは _ViewImportsファイルに追加します。When using a custom folder to hold the app's components, add the namespace representing the folder to either the page/view or to the _ViewImports.cshtml file. たとえば、行が次のように表示されているとします。In the following example:

  • MyAppNamespace をアプリの名前空間に変更します。Change MyAppNamespace to the app's namespace.
  • コンポーネントという名前のフォルダーを使用してコンポーネントを保持していない場合は、コンポーネントが存在するフォルダーに Components を変更します。If a folder named Components isn't used to hold the components, change Components to the folder where the components reside.
@using MyAppNamespace.Components

_ViewImportsのファイルは、Razor Pages アプリのPagesフォルダーまたは MVC アプリのViewsフォルダーにあります。The _ViewImports.cshtml file is located in the Pages folder of a Razor Pages app or the Views folder of an MVC app.

ページまたはビューからコンポーネントを表示するには、Component タグヘルパーを使用します。To render a component from a page or view, use the Component Tag Helper:

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-IncrementAmount="10" />

パラメーターの引き渡し (たとえば、前の例では IncrementAmount) はサポートされています。Passing parameters (for example, IncrementAmount in the preceding example) is supported.

コンポーネントの RenderMode を構成します。RenderMode configures whether the component:

  • ページに prerendered ます。Is prerendered into the page.
  • は、ページに静的な HTML として表示されるか、またはユーザーエージェントから Blazor アプリをブートストラップするために必要な情報が含まれている場合に表示されます。Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.
RenderMode 説明Description
ServerPrerendered コンポーネントを静的 HTML にレンダリングし、Blazor サーバーアプリのマーカーを含めます。Renders the component into static HTML and includes a marker for a Blazor Server app. ユーザーエージェントが起動すると、このマーカーは Blazor アプリをブートストラップするために使用されます。When the user-agent starts, this marker is used to bootstrap a Blazor app.
Server Blazor サーバーアプリのマーカーをレンダリングします。Renders a marker for a Blazor Server app. コンポーネントからの出力は含まれていません。Output from the component isn't included. ユーザーエージェントが起動すると、このマーカーは Blazor アプリをブートストラップするために使用されます。When the user-agent starts, this marker is used to bootstrap a Blazor app.
Static コンポーネントを静的 HTML にレンダリングします。Renders the component into static HTML.

ページとビューはコンポーネントを使用できますが、逆の場合は真実ではありません。While pages and views can use components, the converse isn't true. コンポーネントでは、ビューおよびページ固有のシナリオ (部分ビューやセクションなど) を使用できません。Components can't use view- and page-specific scenarios, such as partial views and sections. コンポーネントの部分ビューからロジックを使用するには、部分ビューのロジックをコンポーネントにします。To use logic from partial view in a component, factor out the partial view logic into a component.

静的な HTML ページからのサーバーコンポーネントのレンダリングはサポートされていません。Rendering server components from a static HTML page isn't supported.

コンポーネントのレンダリング方法、コンポーネントの状態、および Component タグヘルパーの詳細については、「Blazor ホスティングモデルの ASP.NET Core」を参照してください。For more information on how components are rendered, component state, and the Component Tag Helper, see Blazor ホスティングモデルの ASP.NET Core.

コンポーネントを使う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.

属性のバインドでは大文字と小文字が区別されます。Attribute binding is case sensitive. たとえば、@bind が有効で、@Bind が無効です。For example, @bind is valid, and @Bind is invalid.

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

<HeadingComponent />

Components/HeadingComponent: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 statement for the component's namespace makes the component available, which removes the warning.

コンポーネントのパラメーター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="OnClick">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClick { 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"
                OnClick="@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="OnClick">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClick { 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"
                OnClick="@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. Splatted Razor ディレクティブ@attributesを使用してコンポーネントがレンダリングされるときに、ディクショナリ内で追加の属性をキャプチャし、要素にすることができます。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. コンポーネントは、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 が splatted されると、属性は右から左 (最後から順) に処理されます。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" />

データ バインディングData binding

コンポーネントと DOM 要素の両方に対するデータバインディングは、 @bind属性を使用して行われます。Data binding to both components and DOM elements is accomplished with the @bind attribute. 次の例では、CurrentValue プロパティをテキストボックスの値にバインドします。The following example binds a CurrentValue property to the text box's value:

<input @bind="CurrentValue" />

@code {
    private string CurrentValue { get; set; }
}

テキストボックスがフォーカスを失うと、プロパティの値が更新されます。When the text box loses focus, the property's value is updated.

テキストボックスは、プロパティの値の変更に対する応答ではなく、コンポーネントがレンダリングされたときにのみ UI で更新されます。The text box is updated in the UI only when the component is rendered, not in response to changing the property's value. イベントハンドラーのコードを実行した後にコンポーネントがレンダリングされるため、通常、イベントハンドラーがトリガーされた直後に、プロパティの更新が UI に反映されます。Since components render themselves after event handler code executes, property updates are usually reflected in the UI immediately after an event handler is triggered.

CurrentValue プロパティ (<input @bind="CurrentValue" />) で @bind を使用することは、基本的に次のようなものです。Using @bind with the CurrentValue property (<input @bind="CurrentValue" />) is essentially equivalent to the following:

<input value="@CurrentValue"
    @onchange="@((ChangeEventArgs __e) => CurrentValue = 
        __e.Value.ToString())" />
        
@code {
    private string CurrentValue { get; set; }
}

コンポーネントがレンダリングされると、入力要素の valueCurrentValue プロパティから取得されます。When the component is rendered, the value of the input element comes from the CurrentValue property. ユーザーがテキストボックスに入力し、要素のフォーカスを変更すると、onchange イベントが発生し、CurrentValue プロパティが変更された値に設定されます。When the user types in the text box and changes element focus, the onchange event is fired and the CurrentValue property is set to the changed value. 実際には、型変換が実行されるケースが @bind によって処理されるため、コード生成はより複雑になります。In reality, the code generation is more complex because @bind handles cases where type conversions are performed. 原則として、@bind は、式の現在の値を value 属性と関連付け、登録されたハンドラーを使用して変更を処理します。In principle, @bind associates the current value of an expression with a value attribute and handles changes using the registered handler.

@bind 構文を使用した onchange イベントの処理に加えて、event パラメーター (@bind-value:event) を使用して@bind-value属性を指定することで、プロパティまたはフィールドを他のイベントを使用してバインドできます。In addition to handling onchange events with @bind syntax, a property or field can be bound using other events by specifying an @bind-value attribute with an event parameter (@bind-value:event). 次の例では、oninput イベントの CurrentValue プロパティをバインドします。The following example binds the CurrentValue property for the oninput event:

<input @bind-value="CurrentValue" @bind-value:event="oninput" />

@code {
    private string CurrentValue { get; set; }
}

要素がフォーカスを失ったときに発生する onchangeとは異なり、テキストボックスの値が変更されたときに oninput が発生します。Unlike onchange, which fires when the element loses focus, oninput fires when the value of the text box changes.

前の例の @bind-value は、次のようにバインドします。@bind-value in the preceding example binds:

  • 要素の value 属性に対して指定された式 (CurrentValue)。The specified expression (CurrentValue) to the element's value attribute.
  • @bind-value:eventによって指定されたイベントへの変更イベントデリゲート。A change event delegate to the event specified by @bind-value:event.

解析不可能値Unparsable values

データバインド要素に解析できない値を指定すると、バインドイベントがトリガーされたときに、解析されていない値が自動的に前の値に戻されます。When a user provides an unparsable value to a databound element, the unparsable value is automatically reverted to its previous value when the bind event is triggered.

このような場合は、まず、次のことを確認してください。Consider the following scenario:

  • <input> 要素は、初期値 123を持つ int 型にバインドされます。An <input> element is bound to an int type with an initial value of 123:

    <input @bind="MyProperty" />
    
    @code {
        [Parameter]
        public int MyProperty { get; set; } = 123;
    }
    
  • ユーザーは、要素の値をページの 123.45 に更新し、要素のフォーカスを変更します。The user updates the value of the element to 123.45 in the page and changes the element focus.

前のシナリオでは、要素の値が 123に戻されます。In the preceding scenario, the element's value is reverted to 123. 123の元の値を優先して 123.45 値が拒否された場合、ユーザーはその値が受け入れられていないことを認識します。When the value 123.45 is rejected in favor of the original value of 123, the user understands that their value wasn't accepted.

既定では、バインドは要素の onchange イベント (@bind="{PROPERTY OR FIELD}") に適用されます。By default, binding applies to the element's onchange event (@bind="{PROPERTY OR FIELD}"). 別のイベントを設定するには、@bind-value="{PROPERTY OR FIELD}" @bind-value:event={EVENT} を使用します。Use @bind-value="{PROPERTY OR FIELD}" @bind-value:event={EVENT} to set a different event. oninput イベント (@bind-value:event="oninput") の場合、解析できない値を導入するキーストロークの後に再設定が発生します。For the oninput event (@bind-value:event="oninput"), the reversion occurs after any keystroke that introduces an unparsable value. intバインドされた型の oninput イベントを対象とする場合、ユーザーは . 文字を入力できません。When targeting the oninput event with an int-bound type, a user is prevented from typing a . character. . 文字はすぐに削除されるので、ユーザーは、整数のみが許可されるというフィードバックをすぐに受け取ることができます。A . character is immediately removed, so the user receives immediate feedback that only whole numbers are permitted. oninput イベントの値を元に戻すことは、ユーザーが解析できない <input> 値のクリアを許可する必要がある場合など、理想的ではありません。There are scenarios where reverting the value on the oninput event isn't ideal, such as when the user should be allowed to clear an unparsable <input> value. 代替手段は次のとおりです。Alternatives include:

  • oninput イベントは使用しないでください。Don't use the oninput event. 既定の onchange イベント (@bind="{PROPERTY OR FIELD}") を使用します。この場合、要素がフォーカスを失うまで無効な値は元に戻されません。Use the default onchange event (@bind="{PROPERTY OR FIELD}"), where an invalid value isn't reverted until the element loses focus.
  • int?stringなどの null 許容型にバインドし、無効なエントリを処理するカスタムロジックを提供します。Bind to a nullable type, such as int? or string, and provide custom logic to handle invalid entries.
  • InputNumberInputDateなどのフォーム検証コンポーネントを使用します。Use a form validation component, such as InputNumber or InputDate. フォーム検証コンポーネントには、無効な入力を管理するためのサポートが組み込まれています。Form validation components have built-in support to manage invalid inputs. フォーム検証コンポーネント:Form validation components:
    • ユーザーが無効な入力を提供し、関連付けられた EditContextで検証エラーを受信することを許可します。Permit the user to provide invalid input and receive validation errors on the associated EditContext.
    • 追加の web フォームデータを入力するユーザーに干渉することなく、UI に検証エラーを表示します。Display validation errors in the UI without interfering with the user entering additional webform data.

グローバリゼーションGlobalization

@bind 値は、現在のカルチャの規則を使用して表示および解析するように書式設定されます。@bind values are formatted for display and parsed using the current culture's rules.

現在のカルチャには、System.Globalization.CultureInfo.CurrentCulture プロパティからアクセスできます。The current culture can be accessed from the System.Globalization.CultureInfo.CurrentCulture property.

InvariantCultureは、次のフィールドの種類 (<input type="{TYPE}" />) に使用されます。CultureInfo.InvariantCulture is used for the following field types (<input type="{TYPE}" />):

  • date
  • number

上記のフィールド型は次のとおりです。The preceding field types:

  • は、適切なブラウザーベースの書式規則を使用して表示されます。Are displayed using their appropriate browser-based formatting rules.
  • 自由形式のテキストを含めることはできません。Can't contain free-form text.
  • ブラウザーの実装に基づいてユーザーの操作特性を指定します。Provide user interaction characteristics based on the browser's implementation.

次のフィールド型には特定の書式設定要件がありますが、Blazor で現在サポートされていないのは、すべての主要なブラウザーでサポートされていないためです。The following field types have specific formatting requirements and aren't currently supported by Blazor because they aren't supported by all major browsers:

  • datetime-local
  • month
  • week

@bind では、@bind:culture パラメーターを使用して、値の解析および書式設定のための System.Globalization.CultureInfo を提供します。@bind supports the @bind:culture parameter to provide a System.Globalization.CultureInfo for parsing and formatting a value. date および number のフィールドの種類を使用する場合は、カルチャを指定しないことをお勧めします。Specifying a culture isn't recommended when using the date and number field types. datenumber には、必要なカルチャを提供する Blazor サポートが組み込まれています。date and number have built-in Blazor support that provides the required culture.

ユーザーのカルチャを設定する方法については、「ローカリゼーション」セクションを参照してください。For information on how to set the user's culture, see the Localization section.

書式指定文字列Format strings

データバインディングは、 @bind:formatを使用して DateTime 書式指定文字列で動作します。Data binding works with DateTime format strings using @bind:format. 通貨形式や数値形式など、その他の書式指定式は現時点では使用できません。Other format expressions, such as currency or number formats, aren't available at this time.

<input @bind="StartDate" @bind:format="yyyy-MM-dd" />

@code {
    [Parameter]
    public DateTime StartDate { get; set; } = new DateTime(2020, 1, 1);
}

前のコードでは、<input> 要素のフィールドの種類 (type) は既定で textに設定されています。In the preceding code, the <input> element's field type (type) defaults to text. @bind:format は、次の .NET 型のバインドに対してサポートされています。@bind:format is supported for binding the following .NET types:

@bind:format 属性は、<input> 要素の value に適用する日付形式を指定します。The @bind:format attribute specifies the date format to apply to the value of the <input> element. この形式は、onchange イベントが発生したときに値を解析するためにも使用されます。The format is also used to parse the value when an onchange event occurs.

Blazor に日付の書式を設定するためのサポートが組み込まれているため、date フィールド型の形式を指定することは推奨されません。Specifying a format for the date field type isn't recommended because Blazor has built-in support to format dates. 推奨事項では、date フィールドの種類で形式が指定されている場合、バインドの yyyy-MM-dd 日付形式のみを使用することをお勧めします。In spite of the recommendation, only use the yyyy-MM-dd date format for binding to work correctly if a format is supplied with the date field type:

<input type="date" @bind="StartDate" @bind:format="yyyy-MM-dd">

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

バインディングはコンポーネントパラメーターを認識しますが、@bind-{property} はコンポーネント間でプロパティ値をバインドできます。Binding recognizes component parameters, where @bind-{property} can bind a property value across components.

次の子コンポーネント (ChildComponent) には、Year コンポーネントパラメーターと YearChanged コールバックがあります。The following child component (ChildComponent) has a Year component parameter and YearChanged callback:

<h2>Child Component</h2>

<p>Year: @Year</p>

@code {
    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }
}

EventCallback<T> については、「 Eventcallback 」セクションを参照してください。EventCallback<T> is explained in the EventCallback section.

次の親コンポーネントは ChildComponent を使用し、親の ParentYear パラメーターを子コンポーネントの Year パラメーターにバインドします。The following parent component uses ChildComponent and binds the ParentYear parameter from the parent to the Year parameter on the child component:

@page "/ParentComponent"

<h1>Parent Component</h1>

<p>ParentYear: @ParentYear</p>

<ChildComponent @bind-Year="ParentYear" />

<button class="btn btn-primary" @onclick="ChangeTheYear">
    Change Year to 1986
</button>

@code {
    [Parameter]
    public int ParentYear { get; set; } = 1978;

    private void ChangeTheYear()
    {
        ParentYear = 1986;
    }
}

ParentComponent を読み込むと、次のマークアップが生成されます。Loading the ParentComponent produces the following markup:

<h1>Parent Component</h1>

<p>ParentYear: 1978</p>

<h2>Child Component</h2>

<p>Year: 1978</p>

ParentComponentのボタンを選択して ParentYear プロパティの値が変更された場合は、ChildComponentYear プロパティが更新されます。If the value of the ParentYear property is changed by selecting the button in the ParentComponent, the Year property of the ChildComponent is updated. Year の新しい値は、ParentComponent が再度実行されたときに UI に表示されます。The new value of Year is rendered in the UI when the ParentComponent is rerendered:

<h1>Parent Component</h1>

<p>ParentYear: 1986</p>

<h2>Child Component</h2>

<p>Year: 1986</p>

Year パラメーターは、Year パラメーターの型と一致するコンパニオン YearChanged イベントがあるため、バインド可能です。The Year parameter is bindable because it has a companion YearChanged event that matches the type of the Year parameter.

慣例により、<ChildComponent @bind-Year="ParentYear" /> は基本的には書き込みと同じです。By convention, <ChildComponent @bind-Year="ParentYear" /> is essentially equivalent to writing:

<ChildComponent @bind-Year="ParentYear" @bind-Year:event="YearChanged" />

一般に、プロパティは、@bind-property:event 属性を使用して、対応するイベントハンドラーにバインドできます。In general, a property can be bound to a corresponding event handler using @bind-property:event attribute. たとえば、プロパティ MyProp は、次の2つの属性を使用して MyEventHandler にバインドできます。For example, the property MyProp can be bound to MyEventHandler using the following two attributes:

<MyComponent @bind-MyProp="MyValue" @bind-MyProp:event="MyEventHandler" />

ラジオ ボタンRadio buttons

フォームのオプションボタンへのバインドの詳細については、「フォームと検証の Blazor の ASP.NET Core」を参照してください。For information on binding to radio buttons in a form, see フォームと検証の Blazor の ASP.NET Core.

イベント処理Event handling

Razor コンポーネントは、イベント処理機能を提供します。Razor components provide event handling features. on{EVENT} という名前の HTML 要素属性 (onclickonsubmitなど) とデリゲート型の値がある場合、Razor コンポーネントはその属性の値をイベントハンドラーとして扱います。For an HTML element attribute named on{EVENT} (for example, onclick and onsubmit) with a delegate-typed value, Razor components treats the attribute's value as an event handler. 属性の名前は常に@on{EVENT}書式設定されます。The attribute's name is always formatted @on{EVENT}.

次のコードは、UI でボタンが選択されたときに UpdateHeading メソッドを呼び出します。The following code calls the UpdateHeading method when the button is selected in the UI:

<button class="btn btn-primary" @onclick="UpdateHeading">
    Update heading
</button>

@code {
    private void UpdateHeading(MouseEventArgs e)
    {
        ...
    }
}

次のコードは、UI でチェックボックスが変更されたときに CheckChanged メソッドを呼び出します。The following code calls the CheckChanged method when the check box is changed in the UI:

<input type="checkbox" class="form-check-input" @onchange="CheckChanged" />

@code {
    private void CheckChanged()
    {
        ...
    }
}

イベントハンドラーを非同期にして、Taskを返すこともできます。Event handlers can also be asynchronous and return a Task. Statehaschangedを手動で呼び出す必要はありません。There's no need to manually call StateHasChanged. 例外は、発生するとログに記録されます。Exceptions are logged when they occur.

次の例では、ボタンが選択されると UpdateHeading が非同期に呼び出されます。In the following example, UpdateHeading is called asynchronously when the button is selected:

<button class="btn btn-primary" @onclick="UpdateHeading">
    Update heading
</button>

@code {
    private async Task UpdateHeading(MouseEventArgs e)
    {
        ...
    }
}

イベント引数の型Event argument types

イベントによっては、イベント引数の型が許可されます。For some events, event argument types are permitted. これらのイベントの種類のいずれかにアクセスする必要がない場合は、メソッドの呼び出しで必要とされません。If access to one of these event types isn't necessary, it isn't required in the method call.

次の表に、サポートされている EventArgs を示します。Supported EventArgs are shown in the following table.

EventEvent <クラス> のすべてのオブジェクトClass DOM のイベントとメモDOM events and notes
クリップボードのトピックClipboard ClipboardEventArgs oncutでは、 oncopyでは、 onpasteoncut, oncopy, onpaste
ドラッグDrag DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragendondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer および DataTransferItem ドラッグした項目データを保持します。DataTransfer and DataTransferItem hold dragged item data.
エラーError ErrorEventArgs onerror
EventEvent EventArgs 全般General
onactivateonbeforeactivateonbeforedeactivateondeactivateonendedonfullscreenchangeonfullscreenerroronloadeddataonloadedmetadataonpointerlockchangeonpointerlockerroronreadystatechangeonscrollonactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onended, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

クリップボードClipboard
onbeforecutでは、 onbeforecopyでは、 onbeforepasteonbeforecut, onbeforecopy, onbeforepaste

入力Input
oninvalidonresetonselectonselectionchangeonselectstartonsubmitoninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

メディアMedia
oncanplayoncanplaythroughoncuechangeondurationchangeonemptiedonpauseonplayonplayingonratechangeonseekedonseekingonstalledonstop、および onsuspendoncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, onvolumechange, onwaiting
フォーカスFocus FocusEventArgs onfocus, onblur, onfocusin, onfocusoutonfocus, onblur, onfocusin, onfocusout

には relatedTargetのサポートは含まれていません。Doesn't include support for relatedTarget.
[入力]Input ChangeEventArgs onchangeoninputonchange, oninput
キーボードKeyboard KeyboardEventArgs onkeydownでは、 onkeypressでは、 onkeyuponkeydown, onkeypress, onkeyup
マウスMouse MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseoutonclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
マウス ポインターMouse pointer PointerEventArgs onpointerdownonpointeruponpointercancelonpointermoveonpointeroveronpointeroutonpointerenteronpointerleaveongotpointercaptureonlostpointercaptureonpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
マウス ホイールMouse wheel WheelEventArgs onwheelonmousewheelonwheel, onmousewheel
Progress ProgressEventArgs onabortonloadonloadendonloadstartonprogressontimeoutonabort, onload, onloadend, onloadstart, onprogress, ontimeout
タッチTouch TouchEventArgs ontouchstartontouchendontouchmoveontouchenterontouchleaveontouchcancelontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint は、タッチを区別するデバイス上の1つの連絡先ポイントを表します。TouchPoint represents a single contact point on a touch-sensitive device.

前の表に示したイベントのプロパティとイベント処理動作の詳細については、「参照ソースの EventArgs クラス (dotnet/aspnetcore release/3.1 分岐)」を参照してください。For information on the properties and event handling behavior of the events in the preceding table, see EventArgs classes in the reference source (dotnet/aspnetcore release/3.1 branch).

ラムダ式Lambda expressions

ラムダ式を使用することもできます。Lambda expressions can also be used:

<button @onclick="@(e => Console.WriteLine("Hello, world!"))">Say hello</button>

多くの場合、要素のセットを反復処理するときなど、追加の値を終了すると便利です。It's often convenient to close over additional values, such as when iterating over a set of elements. 次の例では、3つのボタンを作成します。各ボタンは、UI で選択されたときに、イベント引数 (MouseEventArgs) とそのボタン番号 (buttonNumber) を渡す UpdateHeading を呼び出します。The following example creates three buttons, each of which calls UpdateHeading passing an event argument (MouseEventArgs) and its button number (buttonNumber) when selected in the UI:

<h2>@message</h2>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <button class="btn btn-primary"
            @onclick="@(e => UpdateHeading(e, buttonNumber))">
        Button #@i
    </button>
}

@code {
    private string message = "Select a button to learn its position.";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        message = $"You selected Button #{buttonNumber} at " +
            $"mouse position: {e.ClientX} X {e.ClientY}.";
    }
}

注意

ラムダ式では、for ループでループ変数 (i) を直接使用しないでください。Do not use the loop variable (i) in a for loop directly in a lambda expression. それ以外の場合、すべてのラムダ式で同じ変数が使用され、iの値はすべてのラムダで同じになります。Otherwise the same variable is used by all lambda expressions causing i's value to be the same in all lambdas. 常にローカル変数 (前の例ではbuttonNumber) で値をキャプチャし、それを使用します。Always capture its value in a local variable (buttonNumber in the preceding example) and then use it.

EventCallbackEventCallback

入れ子になったコンポーネントの一般的なシナリオとして、子コンポーネントのイベント—が発生したときに親コンポーネントのメソッドを実行することが望まれます。たとえば、子で onclick イベントが発生した場合などです。A common scenario with nested components is the desire to run a parent component's method when a child component event occurs—for example, when an onclick event occurs in the child. コンポーネント間でイベントを公開するには、EventCallbackを使用します。To expose events across components, use an EventCallback. 親コンポーネントは、コールバックメソッドを子コンポーネントの EventCallbackに割り当てることができます。A parent component can assign a callback method to a child component's EventCallback.

サンプルアプリ (Components/ChildComponent. razor) の ChildComponent は、ボタンの onclick ハンドラーが、サンプルの ParentComponentから EventCallback デリゲートを受け取るように設定されている方法を示しています。The ChildComponent in the sample app (Components/ChildComponent.razor) demonstrates how a button's onclick handler is set up to receive an EventCallback delegate from the sample's ParentComponent. EventCallbackMouseEventArgsで入力されます。これは、周辺機器の onclick イベントに適しています。The EventCallback is typed with MouseEventArgs, which is appropriate for an onclick event from a peripheral device:

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

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

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

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

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

ParentComponent は、子の EventCallback<T>ShowMessage メソッドに設定します。The ParentComponent sets the child's EventCallback<T> to its ShowMessage method.

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

@page "/ParentComponent"

<h1>Parent-child example</h1>

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

<p><b>@messageText</b></p>

@code {
    private string messageText;

    private void ShowMessage(MouseEventArgs e)
    {
        messageText = $"Blaze a new trail with Blazor! ({e.ScreenX}, {e.ScreenY})";
    }
}

ChildComponentでボタンが選択されている場合:When the button is selected in the ChildComponent:

  • ParentComponentShowMessage メソッドが呼び出されます。The ParentComponent's ShowMessage method is called. messageText が更新され、ParentComponentに表示されます。messageText is updated and displayed in the ParentComponent.
  • このコールバックのメソッド (ShowMessage) では、 Statehaschangedの呼び出しは必要ありません。A call to StateHasChanged isn't required in the callback's method (ShowMessage). StateHasChanged は、子イベントと同様に、子の内部で実行されるイベントハンドラーでコンポーネントの実行がトリガーされるのと同様に、ParentComponentをレンダリングするために自動的に呼び出されます。StateHasChanged is called automatically to rerender the ParentComponent, just as child events trigger component rerendering in event handlers that execute within the child.

EventCallback および EventCallback<T> 非同期デリゲートを許可します。EventCallback and EventCallback<T> permit asynchronous delegates. EventCallback<T> は厳密に型指定され、特定の引数型を必要とします。EventCallback<T> is strongly typed and requires a specific argument type. EventCallback は弱く型指定され、任意の引数型を使用できます。EventCallback is weakly typed and allows any argument type.

<p><b>@messageText</b></p>

@{ var message = "Default Text"; }

<ChildComponent 
    OnClick="@(async () => { await Task.Yield(); messageText = "Blaze It!"; })" />

@code {
    private string messageText;
}

InvokeAsyncEventCallback または EventCallback<T> を呼び出し、Taskを待機します。Invoke an EventCallback or EventCallback<T> with InvokeAsync and await the Task:

await callback.InvokeAsync(arg);

イベント処理とバインドコンポーネントのパラメーターには、EventCallbackEventCallback<T> を使用します。Use EventCallback and EventCallback<T> for event handling and binding component parameters.

厳密に型指定された EventCallback<T> EventCallbackを優先します。Prefer the strongly typed EventCallback<T> over EventCallback. EventCallback<T> は、コンポーネントのユーザーに対してより適切なエラーフィードバックを提供します。EventCallback<T> provides better error feedback to users of the component. 他の UI イベントハンドラーと同様に、イベントパラメーターの指定は省略可能です。Similar to other UI event handlers, specifying the event parameter is optional. コールバックに値が渡されない場合は、EventCallback を使用します。Use EventCallback when there's no value passed to the callback.

既定のアクションを禁止するPrevent default actions

イベントの既定のアクションを回避するには、 @on{EVENT}:preventDefaultディレクティブ属性を使用します。Use the @on{EVENT}:preventDefault directive attribute to prevent the default action for an event.

入力デバイスでキーが選択され、要素のフォーカスがテキストボックスに表示されている場合は、通常、ブラウザーによってテキストボックスにキーの文字が表示されます。When a key is selected on an input device and the element focus is on a text box, a browser normally displays the key's character in the text box. 次の例では、@onkeypress:preventDefault ディレクティブ属性を指定することで、既定の動作を回避できます。In the following example, the default behavior is prevented by specifying the @onkeypress:preventDefault directive attribute. カウンターがインクリメントされ、 + キーが <input> 要素の値にキャプチャされません。The counter increments, and the + key isn't captured into the <input> element's value:

<input value="@_count" @onkeypress="KeyHandler" @onkeypress:preventDefault />

@code {
    private int _count = 0;

    private void KeyHandler(KeyboardEventArgs e)
    {
        if (e.Key == "+")
        {
            _count++;
        }
    }
}

値を指定せずに @on{EVENT}:preventDefault 属性を指定することは @on{EVENT}:preventDefault="true"と同じです。Specifying the @on{EVENT}:preventDefault attribute without a value is equivalent to @on{EVENT}:preventDefault="true".

属性の値は、式にすることもできます。The value of the attribute can also be an expression. 次の例では、_shouldPreventDefaulttrue または falseのいずれかに設定された bool フィールドです。In the following example, _shouldPreventDefault is a bool field set to either true or false:

<input @onkeypress:preventDefault="_shouldPreventDefault" />

既定のアクションを防ぐために、イベントハンドラーは必要ありません。An event handler isn't required to prevent the default action. イベントハンドラーを使用したり、既定のアクションシナリオを回避したりすることができます。The event handler and prevent default action scenarios can be used independently.

イベントの伝達の停止Stop event propagation

イベントの伝達を停止するには、 @on{EVENT}:stopPropagationディレクティブ属性を使用します。Use the @on{EVENT}:stopPropagation directive attribute to stop event propagation.

次の例では、チェックボックスをオンにすると、2番目の子 <div> からのクリックイベントが親 <div>に反映されなくなります。In the following example, selecting the check box prevents click events from the second child <div> from propagating to the parent <div>:

<label>
    <input @bind="_stopPropagation" type="checkbox" />
    Stop Propagation
</label>

<div @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div @onclick="OnSelectChildDiv" @onclick:stopPropagation="_stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

@code {
    private bool _stopPropagation = false;

    private void OnSelectParentDiv() => 
        Console.WriteLine($"The parent div was selected. {DateTime.Now}");
    private void OnSelectChildDiv() => 
        Console.WriteLine($"A child div was selected. {DateTime.Now}");
}

チェーンバインドChained bind

一般的なシナリオでは、データバインドパラメーターをコンポーネントの出力のページ要素に連結します。A common scenario is chaining a data-bound parameter to a page element in the component's output. このシナリオは、複数のレベルのバインドが同時に発生するため、チェーンバインドと呼ばれます。This scenario is called a chained bind because multiple levels of binding occur simultaneously.

チェーンバインドは、ページの要素で @bind 構文を使用して実装することはできません。A chained bind can't be implemented with @bind syntax in the page's element. イベントハンドラーと値は、個別に指定する必要があります。The event handler and value must be specified separately. ただし、親コンポーネントでは、@bind 構文をコンポーネントのパラメーターと共に使用できます。A parent component, however, can use @bind syntax with the component's parameter.

次の PasswordField コンポーネント (Passwordfield):The following PasswordField component (PasswordField.razor):

  • Password プロパティに <input> 要素の値を設定します。Sets an <input> element's value to a Password property.
  • Eventcallbackを使用して、Password プロパティの変更を親コンポーネントに公開します。Exposes changes of the Password property to a parent component with an EventCallback.
Password: 

<input @oninput="OnPasswordChanged" 
       required 
       type="@(showPassword ? "text" : "password")" 
       value="@Password" />

<button class="btn btn-primary" @onclick="ToggleShowPassword">
    Show password
</button>

@code {
    private bool showPassword;

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

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();

        return PasswordChanged.InvokeAsync(Password);
    }

    private void ToggleShowPassword()
    {
        showPassword = !showPassword;
    }
}

PasswordField コンポーネントが別のコンポーネントで使用されています。The PasswordField component is used in another component:

<PasswordField @bind-Password="password" />

@code {
    private string password;
}

前の例で、パスワードの確認またはトラップエラーを実行するには、次の手順を実行します。To perform checks or trap errors on the password in the preceding example:

  • Password のバッキングフィールドを作成します (次のコード例ではpassword)。Create a backing field for Password (password in the following example code).
  • Password setter で、チェックまたはトラップのエラーを実行します。Perform the checks or trap errors in the Password setter.

次の例では、パスワードの値にスペースが使用されている場合に、ユーザーにすぐにフィードバックを提供します。The following example provides immediate feedback to the user if a space is used in the password's value:

Password: 

<input @oninput="OnPasswordChanged" 
       required 
       type="@(showPassword ? "text" : "password")" 
       value="@Password" />

<button class="btn btn-primary" @onclick="ToggleShowPassword">
    Show password
</button>

<span class="text-danger">@validationMessage</span>

@code {
    private bool showPassword;
    private string password;
    private string validationMessage;

    [Parameter]
    public string Password
    {
        get { return password ?? string.Empty; }
        set
        {
            if (password != value)
            {
                if (value.Contains(' '))
                {
                    validationMessage = "Spaces not allowed!";
                }
                else
                {
                    password = value;
                    validationMessage = string.Empty;
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();

        return PasswordChanged.InvokeAsync(Password);
    }

    private void ToggleShowPassword()
    {
        showPassword = !showPassword;
    }
}

コンポーネントへの参照をキャプチャする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. コンポーネント参照は、.NET コードでのみ使用される—JavaScript コードに渡されません。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 の使用法:Usage of 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 attribute ディレクティブは、<div> とその子孫全体を破棄し、新しい要素とコンポーネントで UI 内のサブツリーを再構築する Blazor を強制的に実行します。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.

ルーティング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.

コンポーネントには、複数のルートテンプレートを適用できます。Multiple route templates can be applied to a component. 次のコンポーネントは、/BlazorRoute/DifferentBlazorRouteに対する要求に応答します。The following component responds to requests for /BlazorRoute and /DifferentBlazorRoute.

Pages/BlazorRoute:Pages/BlazorRoute.razor:

@page "/BlazorRoute"
@page "/DifferentBlazorRoute"

<h1>Blazor routing</h1>

ルートパラメーター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 example above. 最初のは、パラメーターを指定せずにコンポーネントへの移動を許可します。The first permits navigation to the component without a parameter. 2番目の @page ディレクティブは、{text} route パラメーターを受け取り、その値を Text プロパティに割り当てます。The second @page directive takes 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).

部分クラスのサポート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 {
    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
    {
        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;

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

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

  • Razor ファイル (razor) マークアップ (@namespace BlazorSample.MyNamespace) の@namespace指定。@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}/ BlazorSample ( ) を名前空間 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:
    • 同じフォルダー内のページ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.

BlazorSample/Shared/ フォルダーに別のコンポーネント (NavMenu.razor) が存在する場合は、次の @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 構文リファレンス.

警告

Ariaなどの一部の HTML 属性は、.net 型が boolの場合、正しく機能しません。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 をレンダリングするには、MarkupString 値で HTML コンテンツをラップします。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>";
}

テンプレートコンポーネントTemplated components

テンプレートコンポーネントは、1つまたは複数の UI テンプレートをパラメーターとして受け取り、コンポーネントのレンダリングロジックの一部として使用できるコンポーネントです。Templated components are components that accept one or more UI templates as parameters, which can then be used as part of the component's rendering logic. テンプレート化されたコンポーネントを使用すると、通常のコンポーネントよりも再利用しやすい上位レベルのコンポーネントを作成できます。Templated components allow you to author higher-level components that are more reusable than regular components. いくつかの例を次に示します。A couple of examples include:

  • テーブルのヘッダー、行、およびフッターのテンプレートをユーザーが指定できるようにするテーブルコンポーネント。A table component that allows a user to specify templates for the table's header, rows, and footer.
  • リスト内の項目を表示するためのテンプレートをユーザーが指定できるようにするリストコンポーネント。A list component that allows a user to specify a template for rendering items in a list.

テンプレート パラメーターTemplate parameters

RenderFragment または RenderFragment<T>型の1つ以上のコンポーネントパラメーターを指定して、テンプレート化されたコンポーネントを定義します。A templated component is defined by specifying one or more component parameters of type RenderFragment or RenderFragment<T>. レンダーフラグメントは、レンダリングする UI のセグメントを表します。A render fragment represents a segment of UI to render. RenderFragment<T> は、レンダリングフラグメントが呼び出されたときに指定できる型パラメーターを受け取ります。RenderFragment<T> takes a type parameter that can be specified when the render fragment is invoked.

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

@typeparam TItem

<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr>@RowTemplate(item)</tr>
        }
    </tbody>
    <tfoot>
        <tr>@TableFooter</tr>
    </tfoot>
</table>

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

    [Parameter]
    public RenderFragment<TItem> RowTemplate { get; set; }

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

    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; }
}

テンプレート化されたコンポーネントを使用する場合、テンプレートパラメーターは、パラメーターの名前と一致する子要素を使用して指定できます (TableHeader と、次の例の RowTemplate)。When using a templated component, the template parameters can be specified using child elements that match the names of the parameters (TableHeader and RowTemplate in the following example):

<TableTemplate Items="pets">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td>@context.PetId</td>
        <td>@context.Name</td>
    </RowTemplate>
</TableTemplate>

テンプレートコンテキストパラメーターTemplate context parameters

要素として渡される型 RenderFragment<T> のコンポーネント引数には、context という名前の暗黙的なパラメーターがあります (たとえば、上記のコードサンプルでは @context.PetId)。ただし、子要素の Context 属性を使用してパラメーター名を変更することもできます。Component arguments of type RenderFragment<T> passed as elements have an implicit parameter named context (for example from the preceding code sample, @context.PetId), but you can change the parameter name using the Context attribute on the child element. 次の例では、RowTemplate 要素の Context 属性で pet パラメーターを指定しています。In the following example, the RowTemplate element's Context attribute specifies the pet parameter:

<TableTemplate Items="pets">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate Context="pet">
        <td>@pet.PetId</td>
        <td>@pet.Name</td>
    </RowTemplate>
</TableTemplate>

または、コンポーネント要素の Context 属性を指定することもできます。Alternatively, you can specify the Context attribute on the component element. 指定された Context 属性は、指定されたすべてのテンプレートパラメーターに適用されます。The specified Context attribute applies to all specified template parameters. これは、暗黙的な子コンテンツ (ラップする子要素を持たない) のコンテンツパラメーター名を指定する場合に便利です。This can be useful when you want to specify the content parameter name for implicit child content (without any wrapping child element). 次の例では、Context 属性が TableTemplate 要素に表示され、すべてのテンプレートパラメーターに適用されます。In the following example, the Context attribute appears on the TableTemplate element and applies to all template parameters:

<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td>@pet.PetId</td>
        <td>@pet.Name</td>
    </RowTemplate>
</TableTemplate>

汎用型のコンポーネントGeneric-typed components

多くの場合、テンプレート化されたコンポーネントは一般的に型指定されますTemplated components are often generically typed. たとえば、汎用 ListViewTemplate コンポーネントを使用して IEnumerable<T> 値を表示できます。For example, a generic ListViewTemplate component can be used to render IEnumerable<T> values. ジェネリックコンポーネントを定義するには、 @typeparamディレクティブを使用して型パラメーターを指定します。To define a generic component, use the @typeparam directive to specify type parameters:

@typeparam TItem

<ul>
    @foreach (var item in Items)
    {
        @ItemTemplate(item)
    }
</ul>

@code {
    [Parameter]
    public RenderFragment<TItem> ItemTemplate { get; set; }

    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; }
}

ジェネリック型のコンポーネントを使用する場合、可能であれば型パラメーターは推論されます。When using generic-typed components, the type parameter is inferred if possible:

<ListViewTemplate Items="pets">
    <ItemTemplate Context="pet">
        <li>@pet.Name</li>
    </ItemTemplate>
</ListViewTemplate>

それ以外の場合は、型パラメーターの名前と一致する属性を使用して、型パラメーターを明示的に指定する必要があります。Otherwise, the type parameter must be explicitly specified using an attribute that matches the name of the type parameter. 次の例では、TItem="Pet" 型を指定しています。In the following example, TItem="Pet" specifies the type:

<ListViewTemplate Items="pets" TItem="Pet">
    <ItemTemplate Context="pet">
        <li>@pet.Name</li>
    </ItemTemplate>
</ListViewTemplate>

カスケード値とパラメーター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.

UiThemeInfo/ :UIThemeClasses/ThemeInfo.cs:

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

先祖コンポーネントでは、カスケード値コンポーネントを使用してカスケード値を指定できます。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.

たとえば、サンプルアプリでは、アプリのいずれかのレイアウトのテーマ情報 (ThemeInfo) を、@Body プロパティのレイアウト本体を構成するすべてのコンポーネントのカスケード型パラメーターとして指定します。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 スニペットを定義する方法であり、次の形式を想定しています。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>Your pet's name is @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>Your pet's name is Rex.</p>

手動の RenderTreeBuilder ロジックManual RenderTreeBuilder logic

Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder には、コンポーネントと要素を操作するためのメソッドがC#用意されていますMicrosoft.AspNetCore.Components.Rendering.RenderTreeBuilder provides methods for manipulating components and elements, including building components manually in C# code.

注意

コンポーネントの作成に RenderTreeBuilder を使用することは、高度なシナリオです。Use of RenderTreeBuilder to create components is an advanced scenario. 形式が正しくないコンポーネント (たとえば、閉じていないマークアップタグなど) は、未定義の動作になる可能性があります。A malformed component (for example, an unclosed markup tag) can result in undefined behavior.

次の PetDetails コンポーネントを検討してください。これは手動で別のコンポーネントに組み込むことができます。Consider the following PetDetails component, which can be manually built into another component:

<h2>Pet Details Component</h2>

<p>@PetDetailsQuote</p>

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

次の例では、CreateComponent メソッドのループによって、3つの PetDetails コンポーネントが生成されます。In the following example, the loop in the CreateComponent method generates three PetDetails components. RenderTreeBuilder メソッドを呼び出してコンポーネント (OpenComponentAddAttribute) を作成する場合、シーケンス番号はソースコードの行番号です。When calling RenderTreeBuilder methods to create the components (OpenComponent and AddAttribute), sequence numbers are source code line numbers. Blazor の相違アルゴリズムは、個別の呼び出し呼び出しではなく、個別のコード行に対応するシーケンス番号に依存します。The Blazor difference algorithm relies on the sequence numbers corresponding to distinct lines of code, not distinct call invocations. RenderTreeBuilder メソッドを使用してコンポーネントを作成する場合は、シーケンス番号の引数をハードコーディングします。When creating a component with RenderTreeBuilder methods, hardcode the arguments for sequence numbers. 計算またはカウンターを使用してシーケンス番号を生成すると、パフォーマンスが低下する可能性があります。Using a calculation or counter to generate the sequence number can lead to poor performance. 詳細については、「シーケンス番号はコード行番号に関連し、実行順序を使用しない」セクションを参照してください。For more information, see the Sequence numbers relate to code line numbers and not execution order section.

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

@page "/BuiltContent"

<h1>Build a component</h1>

@CustomRender

<button type="button" @onclick="RenderComponent">
    Create three Pet Details components
</button>

@code {
    private RenderFragment CustomRender { get; set; }
    
    private RenderFragment CreateComponent() => builder =>
    {
        for (var i = 0; i < 3; i++) 
        {
            builder.OpenComponent(0, typeof(PetDetails));
            builder.AddAttribute(1, "PetDetailsQuote", "Someone's best friend!");
            builder.CloseComponent();
        }
    };    
    
    private void RenderComponent()
    {
        CustomRender = CreateComponent();
    }
}

警告

Microsoft.AspNetCore.Components.RenderTree の型により、レンダリング操作の結果を処理できます。The types in Microsoft.AspNetCore.Components.RenderTree allow processing of the results of rendering operations. これらは、Blazor framework 実装の内部的な詳細です。These are internal details of the Blazor framework implementation. これらの型は不安定であると見なされ、今後のリリースで変更される可能性があります。These types should be considered unstable and subject to change in future releases.

シーケンス番号は、実行順序ではなくコード行番号に関連しますSequence numbers relate to code line numbers and not execution order

Blazor .razor ファイルは常にコンパイルされます。 .razor files are always compiled. コンパイル手順を使用すると、実行時にアプリのパフォーマンスを向上させる情報を挿入できるため、.razor にとって大きな利点があります。This is potentially a great advantage for .razor because the compile step can be used to inject information that improve app performance at runtime.

これらの機能強化の主要な例には、シーケンス番号が含まれます。A key example of these improvements involve sequence numbers. シーケンス番号は、コードの特定の行と順序付けられた行の出力元をランタイムに示します。Sequence numbers indicate to the runtime which outputs came from which distinct and ordered lines of code. ランタイムは、この情報を使用して、効率的なツリーの相違を線形時間で生成します。これは、一般的なツリーの相違アルゴリズムでは通常可能です。The runtime uses this information to generate efficient tree diffs in linear time, which is far faster than is normally possible for a general tree diff algorithm.

次の Razor コンポーネント (razor) ファイルについて考えてみます。Consider the following Razor component (.razor) file:

@if (someFlag)
{
    <text>First</text>
}

Second

上記のコードは、次のようにコンパイルされます。The preceding code compiles to something like the following:

if (someFlag)
{
    builder.AddContent(0, "First");
}

builder.AddContent(1, "Second");

コードを初めて実行するときに、someFlagtrue場合、ビルダーは次のメッセージを受け取ります。When the code executes for the first time, if someFlag is true, the builder receives:

シーケンスSequence の型Type データData
00 テキスト ノードText node FirstFirst
11 テキスト ノードText node SecondSecond

someFlagfalseになり、マークアップが再び表示されるとします。Imagine that someFlag becomes false, and the markup is rendered again. この時点で、ビルダーは次のものを受け取ります。This time, the builder receives:

シーケンスSequence の型Type データData
11 テキスト ノードText node SecondSecond

ランタイムが diff を実行すると、シーケンス 0 の項目が削除されたことが認識されるため、次のような単純な編集スクリプトが生成されます。When the runtime performs a diff, it sees that the item at sequence 0 was removed, so it generates the following trivial edit script:

  • 最初のテキストノードを削除します。Remove the first text node.

プログラムによってシーケンス番号を生成した場合の問題What goes wrong if you generate sequence numbers programmatically

代わりに、次のレンダーツリービルダーのロジックを記述したとします。Imagine instead that you wrote the following render tree builder logic:

var seq = 0;

if (someFlag)
{
    builder.AddContent(seq++, "First");
}

builder.AddContent(seq++, "Second");

これで、最初の出力は次のようになります。Now, the first output is:

シーケンスSequence の型Type データData
00 テキスト ノードText node FirstFirst
11 テキスト ノードText node SecondSecond

この結果は前のケースと同じであるため、負の問題は存在しません。This outcome is identical to the prior case, so no negative issues exist. 2番目のレンダリングでは someFlagfalse、出力は次のようになります。someFlag is false on the second rendering, and the output is:

シーケンスSequence の型Type データData
00 テキスト ノードText node SecondSecond

今回は、diff アルゴリズムによって2 つの変更が行われたことが確認され、アルゴリズムによって次の編集スクリプトが生成されます。This time, the diff algorithm sees that two changes have occurred, and the algorithm generates the following edit script:

  • 最初のテキストノードの値を Secondに変更します。Change the value of the first text node to Second.
  • 2番目のテキストノードを削除します。Remove the second text node.

シーケンス番号を生成すると、if/else 分岐とループが元のコードに存在する場所に関する有用な情報がすべて失われます。Generating the sequence numbers has lost all the useful information about where the if/else branches and loops were present in the original code. これにより、diff は前の2 倍になります。This results in a diff twice as long as before.

これは簡単な例です。This is a trivial example. 複雑で深く入れ子になった構造、特にループを使用したより現実的なケースでは、パフォーマンスコストが高くなります。In more realistic cases with complex and deeply nested structures, and especially with loops, the performance cost is more severe. どのループブロックまたは分岐が挿入または削除されたかをすぐに識別するのではなく、diff アルゴリズムでは、レンダリングツリーに深く再帰する必要があります相互に関連付けられています。Instead of immediately identifying which loop blocks or branches have been inserted or removed, the diff algorithm has to recurse deeply into the render trees and usually build far longer edit scripts because it is misinformed about how the old and new structures relate to each other.

ガイダンスと結論Guidance and conclusions

  • シーケンス番号が動的に生成される場合、アプリのパフォーマンスが低下します。App performance suffers if sequence numbers are generated dynamically.
  • コンパイル時にキャプチャされない場合、必要な情報が存在しないため、実行時にフレームワークで独自のシーケンス番号を自動的に作成することはできません。The framework can't create its own sequence numbers automatically at runtime because the necessary information doesn't exist unless it's captured at compile time.
  • 手動で実装された RenderTreeBuilder ロジックの長いブロックは記述しないでください。Don't write long blocks of manually-implemented RenderTreeBuilder logic. .razor ファイルを優先し、コンパイラがシーケンス番号を処理できるようにします。Prefer .razor files and allow the compiler to deal with the sequence numbers. 手動の RenderTreeBuilder ロジックを回避できない場合は、長いブロックのコードを OpenRegion/CloseRegion 呼び出しでラップされた小さな部分に分割します。If you're unable to avoid manual RenderTreeBuilder logic, split long blocks of code into smaller pieces wrapped in OpenRegion/CloseRegion calls. 各リージョンにはシーケンス番号の個別のスペースがあるため、各リージョン内のゼロ (または任意の任意の数) から再起動できます。Each region has its own separate space of sequence numbers, so you can restart from zero (or any other arbitrary number) inside each region.
  • シーケンス番号がハードコードされている場合、diff アルゴリズムでは、シーケンス番号の値を大きくする必要があります。If sequence numbers are hardcoded, the diff algorithm only requires that sequence numbers increase in value. 初期値とギャップは関係ありません。The initial value and gaps are irrelevant. 正当な選択肢の1つは、コード行番号をシーケンス番号として使用するか、ゼロから開始し、1または数百 (または任意の間隔) で増やすことです。One legitimate option is to use the code line number as the sequence number, or start from zero and increase by ones or hundreds (or any preferred interval).
  • Blazor はシーケンス番号を使用しますが、他のツリー比較 UI フレームワークでは使用しません。 uses sequence numbers, while other tree-diffing UI frameworks don't use them. シーケンス番号を使用すると比較ははるかに高速になります。 また、Blazor には、開発者が razor ファイルを作成するときにシーケンス番号を自動的に処理するコンパイル手順の利点があります。Diffing is far faster when sequence numbers are used, and Blazor has the advantage of a compile step that deals with sequence numbers automatically for developers authoring .razor files.

ローカリゼーションLocalization

Blazor サーバーアプリはローカライズミドルウェアを使用してローカライズされます。 Server apps are localized using Localization Middleware. ミドルウェアは、アプリからリソースを要求するユーザーに適切なカルチャを選択します。The middleware selects the appropriate culture for users requesting resources from the app.

カルチャは、次のいずれかの方法を使用して設定できます。The culture can be set using one of the following approaches:

使用例を含む詳細については、「ASP.NET Core のグローバリゼーションおよびローカリゼーション」を参照してください。For more information and examples, see ASP.NET Core のグローバリゼーションおよびローカリゼーション.

国際化のためのリンカーの構成 (Blazor WebAssemblyConfigure the linker for internationalization (Blazor WebAssembly)

既定では、Blazor WebAssembly に対する Blazor のリンカー構成により、明示的に要求されたロケールを除き、国際化情報は除去されます。By default, Blazor's linker configuration for Blazor WebAssembly apps strips out internationalization information except for locales explicitly requested. リンカーの動作を制御する方法の詳細とガイダンスについては、「ASP.NET Core Blazor 用のリンカーを構成する」を参照してください。For more information and guidance on controlling the linker's behavior, see ASP.NET Core Blazor 用のリンカーを構成する.

CookiesCookies

ローカリゼーションカルチャクッキーは、ユーザーのカルチャを保持できます。A localization culture cookie can persist the user's culture. Cookie は、アプリのホストページ (Pages/host. cshtml. .cs) の OnGet メソッドによって作成されます。The cookie is created by the OnGet method of the app's host page (Pages/Host.cshtml.cs). ローカリゼーションミドルウェアは、後続の要求で cookie を読み取り、ユーザーのカルチャを設定します。The Localization Middleware reads the cookie on subsequent requests to set the user's culture.

Cookie を使用すると、WebSocket 接続がカルチャを正しく伝達できるようになります。Use of a cookie ensures that the WebSocket connection can correctly propagate the culture. ローカライズスキームが URL パスまたはクエリ文字列に基づいている場合は、スキームが Websocket を使用できない可能性があるため、カルチャを永続化できません。If localization schemes are based on the URL path or query string, the scheme might not be able to work with WebSockets, thus fail to persist the culture. したがって、ローカライズカルチャ cookie を使用することをお勧めします。Therefore, use of a localization culture cookie is the recommended approach.

カルチャがローカライズ cookie に保存されている場合は、任意の手法を使用してカルチャを割り当てることができます。Any technique can be used to assign a culture if the culture is persisted in a localization cookie. アプリにサーバー側 ASP.NET Core 用に確立されたローカライズスキームが既にある場合は、引き続きアプリの既存のローカライズインフラストラクチャを使用し、アプリのスキーム内でローカライズカルチャ cookie を設定します。If the app already has an established localization scheme for server-side ASP.NET Core, continue to use the app's existing localization infrastructure and set the localization culture cookie within the app's scheme.

次の例では、ローカリゼーションミドルウェアが読み取ることができる cookie で現在のカルチャを設定する方法を示します。The following example shows how to set the current culture in a cookie that can be read by the Localization Middleware. Blazor Server アプリで次の内容を含むページ/ホストの cshtmlファイルを作成します。Create a Pages/Host.cshtml.cs file with the following contents in the Blazor Server app:

public class HostModel : PageModel
{
    public void OnGet()
    {
        HttpContext.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

ローカライズはアプリで処理されます。Localization is handled in the app:

  1. ブラウザーは、アプリに最初の HTTP 要求を送信します。The browser sends an initial HTTP request to the app.
  2. カルチャは、ローカリゼーションミドルウェアによって割り当てられます。The culture is assigned by the Localization Middleware.
  3. _HostOnGet メソッドは、応答の一部として cookie 内のカルチャを永続化します。The OnGet method in _Host.cshtml.cs persists the culture in a cookie as part of the response.
  4. ブラウザーは、WebSocket 接続を開き、対話型の Blazor サーバーセッションを作成します。The browser opens a WebSocket connection to create an interactive Blazor Server session.
  5. ローカリゼーションミドルウェアは cookie を読み取り、カルチャを割り当てます。The Localization Middleware reads the cookie and assigns the culture.
  6. Blazor サーバーセッションは、正しいカルチャで開始されます。The Blazor Server session begins with the correct culture.

カルチャを選択するための UI を提供するProvide UI to choose the culture

ユーザーがカルチャを選択できるように UI を提供するには、リダイレクトベースのアプローチを使用することをお勧めします。To provide UI to allow a user to select a culture, a redirect-based approach is recommended. このプロセスは、ユーザーがセキュリティで保護されたリソースにアクセスしようとしたときに、ユーザーがサインインページにリダイレクトされ、元のリソースにリダイレクトされる—、web アプリで発生する処理に似ています。The process is similar to what happens in a web app when a user attempts to access a secure resource—the user is redirected to a sign-in page and then redirected back to the original resource.

アプリは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャを永続化します。The app persists the user's selected culture via a redirect to a controller. コントローラーは、ユーザーが選択したカルチャを cookie に設定し、ユーザーを元の URI にリダイレクトします。The controller sets the user's selected culture into a cookie and redirects the user back to the original URI.

Cookie でユーザーが選択したカルチャを設定し、元の URI へのリダイレクトを実行するために、サーバー上に HTTP エンドポイントを確立します。Establish an HTTP endpoint on the server to set the user's selected culture in a cookie and perform the redirect back to the original URI:

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult SetCulture(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

警告

LocalRedirect アクションの結果を使用して、開いているリダイレクト攻撃を防止します。Use the LocalRedirect action result to prevent open redirect attacks. 詳細については、「 ASP.NET Core でのオープンリダイレクト攻撃の防止」を参照してください。For more information, see ASP.NET Core でのオープンリダイレクト攻撃の防止.

次のコンポーネントは、ユーザーがカルチャを選択したときに最初のリダイレクトを実行する方法の例を示しています。The following component shows an example of how to perform the initial redirection when the user selects a culture:

@inject NavigationManager NavigationManager

<h3>Select your language</h3>

<select @onchange="OnSelected">
    <option>Select...</option>
    <option value="en-US">English</option>
    <option value="fr-FR">Français</option>
</select>

@code {
    private double textNumber;

    private void OnSelected(ChangeEventArgs e)
    {
        var culture = (string)e.Value;
        var uri = new Uri(NavigationManager.Uri())
            .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
        var query = $"?culture={Uri.EscapeDataString(culture)}&" +
            $"redirectUri={Uri.EscapeDataString(uri)}";

        NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
    }
}

Blazor アプリで .NET ローカライズシナリオを使用するUse .NET localization scenarios in Blazor apps

Blazor アプリ内では、次の .NET ローカリゼーションとグローバリゼーションのシナリオを利用できます。Inside Blazor apps, the following .NET localization and globalization scenarios are available:

  • .NET のリソースシステム.NET's resources system
  • カルチャ固有の数値と日付の書式設定Culture-specific number and date formatting

Blazor@bind 機能は、ユーザーの現在のカルチャに基づいてグローバリゼーションを実行します。's @bind functionality performs globalization based on the user's current culture. 詳細については、「データバインディング」を参照してください。For more information, see the Data binding section.

現在、次のような ASP.NET Core のローカライズシナリオがサポートされています。A limited set of ASP.NET Core's localization scenarios are currently supported:

  • IStringLocalizer<> は Blazor アプリでサポートされています。IStringLocalizer<> is supported in Blazor apps.
  • IHtmlLocalizer<>IViewLocalizer<>、データ注釈のローカライズは MVC シナリオ ASP.NET Core、Blazor アプリではサポートされていませんIHtmlLocalizer<>, IViewLocalizer<>, and Data Annotations localization are ASP.NET Core MVC scenarios and not supported in Blazor apps.

詳細については、「 ASP.NET Core のグローバリゼーションおよびローカリゼーション」を参照してください。For more information, see ASP.NET Core のグローバリゼーションおよびローカリゼーション.

スケーラブルベクターグラフィックス (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. コンポーネントファイル (razor) に <svg> タグを直接配置した場合、基本的な画像レンダリングはサポートされますが、多くの高度なシナリオはサポートされていません。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> タグは現在尊重されていないため、@bind をいくつかの SVG タグと共に使用することはできません。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