Blazor 入門ステップガイド
Blazorのチュートリアルを開始する
Blazorは、現代のWebアプリ開発で最も人気があり、広く使用されているフレームワークの1つになりつつあります。基本的には、C#、Razor構文、HTML を使用してクライアント側のシングル ページ アプリケーション (SPA) を構築できる .NET Web フレームワークを表します。コンポーネントベースのアーキテクチャ、ページ間での共有可能なUI要素、JavaScriptの相互運用性など、多くのメリットを提供するため、次のプロジェクトで使用を開始する理由はたくさんあります。
BlazorとIgnite UI for Blazorの仕組みをより深く理解するために、このBlazor基本講座ガイドを例、コードスニペット、ユースケースとともに作成しました。
Blazor 基本事項
Blazorとは何ですか?
Blazorは、C#、Razor構文、およびHTMLを使用してクライアント側のアプリケーションを作成できる.NET Webフレームワークです。これにより、C#を使用してリッチで最新のシングルページアプリケーション(SPA)を作成し、任意のブラウザーで実行できます。
「Blazor」という名前は、フレームワークがブラウザーで C# とRazorを実行できることに由来しています。「ブラウザ」と「Razor」を組み合わせた名前が「Blazor」です。
なぜBlazorを使うべきなのか?
- Blazorにより、最新で機能豊富な言語であるC#を使用して、リッチでインタラクティブなUIを作成できます。
- アプリのロジックは、クライアントとサーバーの両方で共有することで再利用できます。これにより、フルスタックの .NET 開発エクスペリエンスを得ることができます。
- 既存の .NET API とツールを使用して、リッチな Web アプリケーションを作成できます。
- Blazorは、Visual Studio と Visual Studio Code の両方でサポートされています。これにより、Linux、Windows、Mac などの複数のプラットフォームで優れた .NET 開発エクスペリエンスが提供されます。
- モバイルブラウザを含むすべての最新のブラウザでサポートされています。
- これは、コミュニティの優れたサポートを備えたオープンソースのフレームワークです。
- IIS、Azure App Service、Docker を使用してアプリを簡単にホストできます。
Blazorの特徴
- コンポーネントベースのアーキテクチャ: Blazor、リッチでコンポーザブルなUIを作成するためのコンポーネントベースのアーキテクチャを提供します
- レイアウト:レイアウト機能を使用して、ページ間で共通の UI 要素 (メニューなど) を共有できます。
- JavaScript の相互運用機能:これにより、JavaScript から C# メソッドを呼び出したり、C# コードから JavaScript 関数や API を呼び出したりすることができます。
- ルーティング:ルーティングの助けを借りて、クライアントリクエストをあるコンポーネントから別のコンポーネントにリダイレクトできます。
- フォームと検証:ユーザー入力を処理するための対話型フォームを作成し、フォーム内のエラーを処理するための検証手法を適用できます。
- 状態管理:ユーザーのアプリの状態をブラウザのメモリに保持できます。ただし、ユーザーがブラウザを再度開いたり、ページを再読み込みしたりすると、ブラウザのメモリに保持されているユーザー状態は失われます。
- グローバリゼーションとローカリゼーション: Blazorアプリは、複数のカルチャや言語のユーザーがアクセスできるようにすることができます。これにより、アプリケーションの範囲を世界中のユーザーに拡大することができます。
- プログレッシブ Web アプリケーション:プログレッシブWebアプリケーションとしてBlazorアプリを作成できます。これにより、Blazorアプリはオフラインで動作し、ユーザーのネットワーク速度に関係なく即座にロードできます。
- 遅延読み込み:遅延読み込みを使用すると、一部のアプリケーションアセンブリの読み込みを必要になるまで遅らせることができます。これにより、アプリケーションの起動パフォーマンスが向上します。
- デバッグ:Microsoft Edge や Google Chrome などの Chromium ベースのブラウザーでBlazor WebAssembly アプリをデバッグできます。また、Firefoxでのデバッグサポートが利用可能になりつつあります(現在、プレビュー段階にあります)。Visual Studio と Visual Studio Code IDE でアプリをデバッグすることもできます。
Blazorホスティングモデル
Blazorのコンポーネントモデルは、UI の変更を計算する役割を担います。ただし、さまざまなレンダラーを使用して、UI の表示方法と更新方法を制御できます。これらのレンダラーは、ホスティング モデルと呼ばれます。
Blazorは 2 つのホスティング モデルをサポートしています
- Blazor WebAssembly
- Blazor Server
サーバー vs WASM vs ハイブリッド
Blazorサーバーとは?
Blazorサーバー ホスティング モデルを使用すると、Blazorアプリケーションを完全な .NET ランタイム上のサーバー上で実行できます。
Blazorサーバーはどのように機能しますか?
Blazorサーバー実行モデルを次の図に示します。
ユーザーがアプリケーションを読み込むと、小さな JavaScript ファイル (blazor.server.js) がブラウザーにダウンロードされ、サーバーとのリアルタイムの双方向 SignalR 接続が確立されます。
アプリとのユーザー操作は、既定では WebSocket プロトコルを使用して SignalR 接続経由でサーバーに送り返されます。サーバーはクライアントの要求を処理します。サーバーが完了すると、UI の更新はクライアントに送り返され、DOM に適用されます。
サーバーは、接続されている各クライアントの状態を保持します。この状態は回線と呼ばれます。
ブラウザでアプリを起動すると、回路が作成されます。ブラウザー内のアプリの各インスタンスは、サーバー上に新しい回線を作成します。これは、同じブラウザの2つの異なるタブでアプリを開くと、サーバー上に2つの回路が作成されることを意味します。
ブラウザを閉じるか、外部 URL に移動してアプリを閉じると、回線と関連リソースはすぐに解放されます。
Blazor Serverを使用する利点
Blazorサーバーには、次の利点があります。
- アプリのダウンロードサイズは、Blazor WebAssembly アプリと比較して大幅に小さくなっています。これにより、アプリの読み込みが速くなります。
- Blazorサーバー アプリは、.NET 互換 API などのサーバー機能を最大限に活用します。
- アプリはサーバー上で実行されるため、デバッグなどの既存の .NET ツールを最大限に活用できます。
- アプリのコード ベースはクライアントと共有されません。
Blazor Serverはいつ使用しますか?
Blazorサーバー アプリは、次のシナリオで推奨されます。
- アプリをすばやく読み込みたい場合。
- アプリがサーバーとネットワーク リソースにアクセスする場合。
- すべてのユーザー操作にはネットワーク ホップが関係するため、Blazorサーバー アプリでは高い待機時間が観察されます。したがって、高遅延が問題にならないBlazorサーバーを使用してください。
- 面倒な作業はすべてサーバーによって行われるため、クライアント リソースが限られている場合はBlazorサーバーが優先されます。
- Blazorサーバーは、WebAssembly をサポートしていないブラウザーに適しています。
Blazor WebAssembly
Blazor WebAssembly とは何ですか?
Blazor WebAssembly(WASM) ホスティング モデルを使用すると、Blazorアプリは WebAssembly ベースの .NET ランタイム上のブラウザーでクライアント側で実行できます。これは、Blazorの主要なホスティングモデルです。
Blazor WebAssembly はどのように機能しますか?
Blazor WASM 実行モデルを次の図に示します。
ユーザーがアプリケーションをロードすると、小さなJavaScriptファイル(blazor.webassembly.js)がブラウザにダウンロードされます。
このファイルは、次の 2 つの操作を処理します。
- .NET ランタイムをBlazorアプリとその依存関係と共にブラウザーにダウンロードします。
- アプリを実行するために .NET ランタイムを初期化します。
アプリの実行は、ブラウザーの UI スレッドで直接行われます。UI の更新とイベント処理も同じプロセス内で行われます。
Web サーバーまたは静的コンテンツをクライアントに提供できるその他のサービスを使用して、アプリのアセットを静的ファイルとしてデプロイできます。
Blazor WebAssembly アプリの種類
WASM アプリにはBlazor次の 2 種類があります。
- スタンドアロン: Blazor WebAssembly アプリが、ファイルを提供するバックエンドASP.NET Coreアプリなしでデプロイ用に作成される場合、そのアプリはスタンドアロンのBlazor WASM アプリと呼ばれます。
- ホスト:アプリが、そのファイルを提供するバックエンド アプリを使用してデプロイ用に作成される場合、そのアプリはホストされたBlazor WASM アプリと呼ばれます。ホステッド アプリは、.NET を使用したフルスタックの Web 開発エクスペリエンスを提供します。これにより、クライアントとサーバーアプリ間でコードを共有し、プリレンダリングとMVCおよびRazorページとの統合をサポートできます。
Blazor WebAssembly を使用する利点
Blazor WebAssemblyには、次の利点があります。
- アプリがクライアントにダウンロードされた以降は、サーバーへの依存がありません。これにより、サーバーがオフラインになった場合でも、アプリは機能し続けることができます。
- クライアントが面倒な作業を行います。したがって、サーバーの負荷が少なくなります。
- アプリは、クライアントのリソースを最大限に活用します。
- アプリをホストするためにサーバーは必要ないため、サーバーレスのデプロイ シナリオがサポートされています。
Blazor WebAssembly はいつ使用しますか?
Blazor WASM アプリは、次のシナリオで推奨されます。
- アプリでクライアントのリソースを活用する場合。
- クライアントがインターネットに接続できない場合にアプリをオフラインで実行する必要がある場合。
- アプリを静的サイトとしてホストする場合。
Blazorハイブリッド
Blazorハイブリッドとは?
Blazor Hybridを使用すると、.NET、HTML、CSSを使用してネイティブクライアントアプリを作成できます。.NET MAUI、WPF、Windows フォームなどの既存の .NET ネイティブ アプリ フレームワークを使用して、Blazorハイブリッド アプリを作成できます。
Blazor Hybridはどのように機能しますか?
Blazorハイブリッド アプリでは、デバイス上で Razor コンポーネントがネイティブに実行されます。Blazorコンポーネントは、ローカル相互運用チャネルを介して埋め込み Web ビュー コントロールにレンダリングされます。コンポーネントは、ブラウザーではなく、ネイティブアプリ上で直接実行されます。したがって、WebAssembly はハイブリッド アプリに関与しません。
ハイブリッド アプリは、.NET API を介してネイティブ プラットフォームの機能にアクセスできます。ネイティブアプリであるBlazorハイブリッドアプリは、Webプラットフォームだけでは利用できない機能をサポートできます。また、BlazorサーバーやBlazor WASMアプリケーションの既存のRazorコンポーネントをBlazorハイブリッドアプリと共有して再利用することもできます。
Blazor Hybridを使用する利点
- これにより、BlazorサーバーとBlazor WASM アプリケーションの既存のコンポーネントを再利用できます。これにより、モバイル、デスクトップ、およびWebプラットフォーム間でのコード共有と再利用が可能になります。
- このアプリは、デバイスのネイティブ機能を活用できます。
Blazorハイブリッドはいつ使用しますか?
Blazor Hybrid アプリは、次のシナリオで推奨されます。
- .NET APIを使用してネイティブアプリを作成する場合。
- ネイティブクライアント機能を利用したいとき。
- アプリをオフラインで実行する必要がある場合。
- アプリのデータ処理をクライアントにオフロードしたい場合
Blazorコンポーネント
Blazorコンポーネントとは何ですか?
Blazorコンポーネントは、ナビゲーションバー、ボタン、フォームなどのUIの一部として定義されBlazorコンポーネントは拡張子「.razor」のRazorコンポーネントファイルとして作成されます。
コンポーネントは再利用可能で、複数のプロジェクト間で共有できます。Blazorコンポーネントは、Razorコンポーネントとも呼ばれます。
Razorは、HTML と C# のコードを組み合わせるためのマークアップ構文です。
Blazorコンポーネントの名前は、大文字で始まる必要があります。
例: – LoginForm.razor という名前は有効なコンポーネント名です。一方、loginForm.razor という名前は無効なコンポーネント名です。
以下に示すコンポーネントコードの例を見てください。
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status" >Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@page ディレクティブは、コンポーネントのルートを指定するために使用されます。@code ディレクティブは、コンポーネントの C# コードを指定するために使用されます。メソッド IncrementCount は、ボタン クリック イベントで呼び出されます。
また、1つのコンポーネントに対して、複数であるが異なる@pageディレクティブを使用することもできます。2つの異なるコンポーネントに同じルートを設定することはできません。これを行うと、ランタイムエラーが発生します。
コンポーネント基本クラス
コンポーネントの基本クラスを作成して、HTML ロジックと C# ロジックを分離できます。基本クラスは、ComponentBase クラスから派生する必要があります。@inherits ディレクティブを使用して、コンポーネント内の基本クラスを継承できます。
以下に示すように、基本クラスWelcome.razor.csを作成しました。
using Microsoft.AspNetCore.Components;
namespace BlazorTutorial.Client.Pages;
public class WelcomeBase : ComponentBase { public string WelcomeMessage { get; set; } = "Welcome to Blazor tutorial."; }
以下に示すように、かみそりコンポーネントWelcome.razorを作成しました。
@page "/welcome"
@inherits WelcomeBase
<h1>@WelcomeMessage</h1>
基本クラスを継承するために @inherits ディレクティブを使用しています。
コンポーネントパラメータ
コンポーネント パラメーターは、親コンポーネントから子コンポーネントにデータを渡すために使用されます。
例の助けを借りてこれを理解しましょう。
次に示すように、コンポーネント Child.razor を作成します。
<h3>Child Component</h3>
<p>The sum of number is : @(num1 + num2)</p>
@code {
[Parameter]
public int num1 { get; set; }
[Parameter]
public int num2 { get; set; }
}
コンポーネント パラメーターには [Parameter] 属性で注釈が付けられます。このコンポーネントは、整数型の 2 つのパラメーターを受け取り、両方の数値の合計を表示します。
次に示すように、別のコンポーネント Parent.razor を作成します。
@page "/parent"
<h3>Parent Component</h3>
<Child num1="5" num2="10"><Child>
親コンポーネント内で子コンポーネントを呼び出し、両方のパラメータを渡しました。
「@」記号を使用して、C# プロパティをパラメーター値に割り当てることもできます。
以下に示す例を見てください。
@page "/parent"
<h3>Parent Component</h3>
<Child num1="@number1" num2="@number2"><Child>
@code {
int number1 = 5;
int number2 = 10;
}
パラメーターは、[EditorRequired] 属性を使用して必須としてマークできます。
以下に示す例を見てください。
<h3>Child Component</h3>
<p>The sum of number is : @(num1 + num2)<p>
@code {
[Parameter]
[EditorRequired]
public int num1 { get; set; }
[Parameter]
[EditorRequired]
public int num2 { get; set; }
}
[EditorRequired] 属性を使用しながら、[Parameter] 属性を使用する必要があります。
コンポーネントの呼び出し中に必要なパラメータを指定しないと、コンパイル時に警告がスローされます。
また、コンポーネントパラメータにデフォルト値を指定することもできます。
以下に示す例を見てください。
@page "/welcome"
<h1>WelcomeMessage</h1>
@code {
[Parameter]
public string WelcomeMessage { get; set; } = "Welcome";
}
Razorコンポーネントのライフサイクル
Razorコンポーネントは、作成から削除されるまで、一連のライフサイクル イベントを経験します。同期メソッドと非同期メソッドの両方があります。Blazorフレームワークを使用すると、ライフサイクルメソッドをオーバーライドして、コンポーネントに対して追加の操作を実行できます。
SetParametersAsync
このメソッドは、パラメータが設定される前に呼び出されます。親コンポーネントまたはコンポーネントルートから提供されるパラメータを設定します。ベースを呼ばなければなりません。SetParametersAsync() メソッドを使用して、コンポーネント パラメーターの値を設定します。それ以外の場合は、パラメーターを操作するためのカスタムコードを記述する必要があります。
OnInitialized
このメソッドは、パラメータが設定される前に呼び出されます。これは、親から初期パラメータを受け取った後、コンポーネントが起動する準備ができたときに呼び出されます。
非同期バージョンは OnInitializedAsync と呼ばれます。非同期操作を実行し、その操作が完了したときにコンポーネントを更新する場合は、OnInitializedAsync をオーバーライドします。
OnParametersSet
このメソッドは、パラメータが設定された後に呼び出されます。これは、コンポーネントが親からパラメーターを受け取り、受信値がプロパティに割り当てられたときに呼び出されます。このメソッドは、パラメータが更新されるたびに実行されます。非同期バージョンは OnParametersSetAsync と呼ばれます。
OnAfterRender
このメソッドは、コンポーネントのレンダリングが完了した後、つまり HTML がすでに表示された後に呼び出されます。このメソッドを使用して、レンダリングされた DOM 要素を使用するサードパーティの JavaScript ライブラリのアクティブ化など、コンポーネントの初期化に必要な追加の手順を実行できます。このメソッドは、コンポーネントがレンダリングされるたびに実行されます。非同期バージョンは OnAfterRenderAsync と呼ばれます。
StateHasChanged
このメソッドは、状態が変更されたことをコンポーネントに通知し、コンポーネントを再レンダリングします。EventCallback 中に、このメソッドが自動的に呼び出され、Parent コンポーネントが再レンダリングされます。
このメソッドを呼び出すと、いつでもコンポーネントをレンダリングできます。ただし、StateHasChanged の呼び出しが多すぎると、アプリケーションに不要なレンダリング コストがかかる可能性があります。
例の助けを借りてこれを理解しましょう。
以下に示すように、基本クラス Lifecycle.razor.cs を作成しました。
using Microsoft.AspNetCore.Components;
namespace BlazorTutorial.Client.Pages;
public class LifecycleBase : ComponentBase { public override async Task SetParametersAsync(ParameterView parameters){ Console.WriteLine("SetParametersAsync-start"); await base.SetParametersAsync(parameters); Console.WriteLine("SetParametersAsync-end"); }
protected override void OnInitialized() { Console.WriteLine("OnInitialized-start"); base.OnInitialized(); Console.WriteLine("OnInitialized-end"); }
protected override async Task OnInitializedAsync() { Console.WriteLine("OnInitializedAsync-start"); await base.OnInitializedAsync(); Console.WriteLine("OnInitializedAsync-end"); }
protected override void OnParametersSet() { Console.WriteLine("OnParametersSet-start"); base.OnParametersSet(); Console.WriteLine("OnParametersSet-end"); }
protected override async Task OnParametersSetAsync() {Console.WriteLine("OnParametersSetAsync-start"); await base.OnParametersSetAsync(); Console.WriteLine("OnParametersSetAsync-end"); }
protected override void OnAfterRender(bool firstRender) { Console.WriteLine("OnAfterRender({0})-start", firstRender); base.OnAfterRender(firstRender); Console.WriteLine("OnAfterRender({0})-end", firstRender); }
protected override async Task OnAfterRenderAsync(bool firstRender) { Console.WriteLine("OnAfterRenderAsync({0})-start", firstRender); await base.OnAfterRenderAsync(firstRender); Console.WriteLine("OnAfterRenderAsync({0})-end", firstRender); } }
以下に示すように、Lifecycle.razorコンポーネントを作成しました。
@page "/lifecycle"
@inherits WelcomeBase
<h1>Blazor component lifecycle example</h1>
アプリケーションを実行してライフサイクルコンポーネントに移動すると、以下に示すようにブラウザコンソールに出力が表示されます。
この出力は、Razorコンポーネントのライフサイクルメソッドの実行シーケンスを示しています。
Blazorカスケード値とパラメータ
カスケード値とパラメータを使用すると、コンポーネントからそのすべての子孫コンポーネントにデータを渡すことができます。コンポーネントは、<CascadingValue> コンポーネントを使用してカスケード値を提供できます。
親コンポーネントによって提供されるカスケード値を利用するために、子コンポーネントは [CascadingParameter] 属性を使用してカスケード パラメーターを宣言できます。
カスケード値は、データ型によってカスケード パラメーターにバインドされます。同じ型の複数の値をカスケードする場合は、各 [CascadingParameter] 属性に一意の名前を付けることができます。
例の助けを借りてこれを理解しましょう。
次に示すように、コンポーネント Child.razor を作成します。
<h3>Child Component</h3>
<p>The sum of number is : @(num1 + num2)</p>
@code {
[CascadingParameter(Name = "FirstNumber")]
public int num1 { get; set; }
[CascadingParameter(Name = "SecondNumber")]
public int num2 { get; set; }
}
次に示すように、コンポーネント Parent.razor を作成します。
@page "/parent"
<h3>Parent Component</h3>
<CascadingValue Value="@number1" Name="FirstNumber" >
<CascadingValue Value="@number2" Name="SecondNumber" >
<Child></Child>
</CascadingValue>
</CascadingValue>
@code {
int number1 = 5;
int number2 = 10;
}
Child コンポーネントを呼び出し、カスケード値を渡しました。子コンポーネントは、Name プロパティを使用してパラメータ値をバインドします。
コンポーネント階層間でデータを渡す
カスケードパラメータを使用して、コンポーネント階層間でデータを渡すことができます。
例の助けを借りてこれを理解しましょう。
次に示すように、コンポーネント GrandChild.razor を作成します。
<h3>Grand Child Component</h3>
<p>The product of number is : @(num1 * num2)</p>
@code {
[CascadingParameter(Name = "FirstNumber")]
public int num1 { get; set; }
[CascadingParameter(Name = "SecondNumber")]
public int num2 { get; set; }
}
次に示すように、コンポーネント Child.razor を作成します。
<h3>Child Component</h3>
<p>The sum of number is : @(num1 + num2)</p>
<GrandChild></GrandChild>
@code {
[Parameter]
public int num1 { get; set; }
[Parameter]
public int num2 { get; set; }
}
@page "/parent"
<h3>Parent Component</h3>
<CascadingValue Value="10" Name="FirstNumber" >
<CascadingValue Value="5" Name="SecondNumber" >
<Child></Child>
</CascadingValue>
</CascadingValue>
@code {
int number1 = 5;
int number2 = 10;
}
カスケード値を Parent コンポーネントから GrandChild コンポーネントに渡しました。カスケード パラメーターの名前は、Child コンポーネントと GrandChild コンポーネントの両方で同じであることに注意してください。
実行すると、次に示すように出力が表示されます。
Blazorデータ バインディング
一方向のデータバインディング
これにより、プロパティの値をHTML DOM要素にバインドできますが、その逆はできません。プロパティまたはフィールドを HTML タグにバインドするには、プロパティ名を @ 記号の先頭に付けて渡す必要があります。
以下に示す例を見てください。
@page "/databinding"
<h3>One way data binding</h3>
<p>@SampleText</p>
@code {
string SampleText = "This is a sample text depicting one-way data-binding";
}
C# フィールド SampleText は、@ 記号を使用して HTML DOM にバインドされます。
双方向のデータバインディング
これにより、プロパティまたはフィールドの値をHTML DOM要素にバインドしたり、その逆を行ったりすることができます。@bind属性を使用して、双方向のデータバインディングを実現できます。
HTML 要素の @bind:event="{EVENT}" 属性を使用して、DOM イベントに C# プロパティをバインドできます。ここで、{EVENT} は DOM イベントのプレースホルダーです。
以下に示す例を見てください。
@page "/databinding"
<h3>Two way data binding</h3>
<div>
<span>Enter your Name: </span>
<input type="text" @bind="Name" @bind:event="oninput" />
</div>
<br/>
<p>You name is: @Name</p>
@code {
string Name { get; set; }
}
入力フィールドの値は、Name プロパティにバインドされます。データバインディングは、入力フィールドのoninputイベントがトリガーされたとき、つまりテキストボックスの値が変更されたときに発生します。
NOTE:
属性バインディングでは、大文字と小文字が区別されます。つまり、@bind、@bind:event は有効ですが、@Bind、@Bind:EVENT など、大文字を使用する構文は無効です。
<select> 要素を使用して複数のオプションをバインドする
複数選択からの値を配列型の C# プロパティにバインドできます。
以下に示す例を見てください。
@page "/databinding"
<p>
<label>
Select one or more days:
<select @onchange="SelectedDaysChanged" multiple >
<option value="monday">Monday</option>
<option value="tuesday">Tuesday</option>
<option value="wednesday">Wednesday</option>
<option value="thursday">Thursday</option>
<option value="friday">Friday</option>
</select>
</label>
</p>
<p>
Selected Days: @string.Join(", ", SelectedDays)
</p>
@code {
public string[] SelectedDays { get; set; } = new string[] { };
void SelectedDaysChanged(ChangeEventArgs e)
{
if (e.Value is not null) {
SelectedDays = (string[])e.Value;
}
}
}
選択した値は、<select> 要素の @onchange イベントを使用して文字列の配列にバインドされます。
書式設定された文字列にバインドする
データバインディングは、構文 @bind:format="{FORMAT STRING}" を使用して書式設定された文字列で機能します
書式設定されたデータ バインディングは、次の .NET 型でサポートされています。
- System.DateTime
- System.DateTimeOffset (英語)
以下に示す例を見てください。
@page "/databinding"
<h3>Formatted string</h3>
<div>
<span>The Sample date is: </span>
<input @bind="SampleDate" @bind:format="dd-MM-yyyy" />
</div>
@code {
DateTime SampleDate { get; set; } = new DateTime(2023, 1, 14);
}
日付は、@bind:format 属性を使用して指定された形式で表示されます。
カスタムバインディング形式は、get アクセサーと set アクセサーを使用して指定できます。
以下に示す例を見てください。
@page "/databinding"
<input @bind="SalaryValue" />
<h3>Formatted string</h3>
<p>
<code>decimalValue</code>: @salary
</p>
@code {
decimal salary = 123456;
string SalaryValue {
get => salary.ToString("0.000");
set {
if (Decimal.TryParse(value, out var number)) {
salary = Math.Round(number, 3);
}
}
}
}
文字列プロパティ SalaryValue は、入力要素に小数点以下 3 桁までバインドされます。
コンポーネントパラメータとのバインディング
子コンポーネントのプロパティを、その親コンポーネントのプロパティにバインドできます。データ バインディングは複数のレベルで行われるため、このシナリオはチェーン バインドと呼ばれます。
構文 @bind-{PROPERTY} を使用できます。ここで、{PROPERTY} はバインドするプロパティのプレースホルダーです。子コンポーネントから親のプロパティの更新をサポートするためのイベントハンドラと値を提供する必要があります。
例の助けを借りてこれを理解しましょう。
次に示すように、コンポーネント Child.razor を作成します。
<h3>Child Component</h3>
<p>Child Message: @Message</p>
<button @onclick="UpdateMessageFromChild">Update Message from Child</button>
@code {
[Parameter]
public string Message { get; set; }
[Parameter]
public EventCallback <string> MessageChanged { get; set; }
private async Task UpdateMessageFromChild() {
await MessageChanged.InvokeAsync("Message from child component");
}
}
string 型のコンポーネント パラメーターと、コンポーネント パラメーターと同じ型の EventCallback を宣言しました。
EventCallback の名前は、構文 {PARAMETER NAME}Changed に従う必要があります。ここで、{PARAMETER NAME} はコンポーネント パラメーター名のプレースホルダーです。他の命名形式を使用すると、ランタイムエラーが発生します。
上記の例では、コンポーネント パラメーターの名前は Message で、EventCallback の名前は MessageChanged です。
次に示すように、コンポーネント Parent.razor を作成します。
@page "/parent"
<h3>Parent Component</h3>
<Child @bind-Message="MesssageFromParent"></Child>
<button @onclick="UpdateMessageFromChild">Update Message from Child</button>
@code {
string MesssageFromParent = "Message from parent component";
}
C# プロパティ MesssageFromParent は、子コンポーネントの Message パラメーターにバインドされています。Child コンポーネントの Message パラメータは、Message パラメータと同じ型のコンパニオン MessageChanged イベントがあるため、バインド可能です。
実行すると、次のような出力が表示されます。
ボタンをクリックするとすぐに、下の画像に示すようにメッセージが更新されます。
Blazorイベント処理
@on{EVENT} という名前の HTML 属性を追加し、委任タイプの値を設定します。この属性の値は、Blazorコンポーネントによってイベント ハンドラとして扱われます。
Blazorでサポートされているイベントハンドラには、@onclick、@onchange、@onselect、@onfocus、@onkeyupなどがあります。
例
<button @onclick="ButtonClicked">Click me</button>
@code {
void ButtonClicked() {
Console.WriteLine("button clicked");
}
}
ボタンをクリックすると、ButtonClickedメソッドが呼び出されます。
非同期イベント処理
以下に示す例を見てください。
<button @onclick="ButtonClicked">Click me</button>
@code {
async Task ButtonClicked() {
await Task.Delay(1000);
Console.WriteLine("button clicked");
}
}
ButtonClicked メソッドは、ボタンがクリックされると非同期的に呼び出されます。
イベント引数の使用
以下に示す例を見てください。
<select class="form-control col-md-4" @onchange="SelectGender" />
<option value="">-- Select Gender --</option>
<option value="Male">Male</option>
<option value="Famale">Famale</option>
</select>
@code {
protected string Gender { get; set; }
protected void SelectGender(ChangeEventArgs e) {
Gender = e.Value.ToString();
}
}
SelectGender メソッドを select 要素の onchange イベントにバインドしました。
イベントメソッド定義でのイベント引数の指定はオプションです。メソッドでイベント引数を使用する場合にのみ必須です。
イベント処理にラムダ式を使用する
ラムダ式を使用して、イベント属性の無名関数を作成できます。
以下に示す例を見てください。
@for (int i = 1; i < 4; i++) {
int textboxNumber = i;
<p>
<input> @onfocus="@(() => FocusTextbox(textboxNumber))" />
</p>
}
@code {
protected string Gender { get; set; }
protected void FocusTextbox(int textboxNumber) {
Console.WriteLine($"You have selected textbox number {textboxNumber}");
}
}
for ループを使用して 3 つのテキスト ボックス コントロールを作成しました。ラムダ式を使用して、各テキスト ボックスの onfocus イベントで FocusTextbox メソッドを呼び出しました。
EventCallback
EventCallback を使用して、複数のコンポーネント間でイベントを公開できます。これは、子コンポーネントでイベントが発生したときに親コンポーネントのメソッドを呼び出すのに役立ちます。
EventCallback は、EventCallback<TValue> という構文を使用してイベント パラメータを指定することで、強く型指定できます。
例: EventCallback<MouseEventArgs>
例の助けを借りてEventCallbackを理解しましょう。
次に示すように、コンポーネント Child.razor を作成します。
<h3>Child Component</h3>
<button class="btn btn-primary"@onclick="ChildClick">
Invoke parent component method
</button>
@code {
[Parameter]
public EventCallback ChildClick { get; set; }
}
次に示すように、別のコンポーネント Parent.razor を作成します。
<h3>Parent Component</h3>
<Child ChildClick="ChildClickHandler"> </Child>
<p><strong> @message </strong></p>
@code {
string message { get; set; }
void ChildClickHandler() {
message = "Child event has occurred";
}
}
子コンポーネントに EventCallback パラメータを作成しました。ボタンの onclick イベント ハンドラーは、ParentComponent から EventCallback デリゲートを受け取るように設定されています。
ParentComponent は、子コンポーネントの EventCallback と ChildClick をその ChildClickHandler メソッドに設定します。
Child コンポーネントのボタンをクリックすると、Parent Component の ChildClickHandler メソッドが呼び出されます。文字列プロパティ メッセージが更新され、ParentComponent に表示されます。
デフォルトアクションの防止
@on{DOM EVENT}:p reventDefault ディレクティブ属性を使用して、イベントのデフォルトアクションを防ぐことができます。この属性は、引数としてブール値を受け入れます。引数を指定しない場合は、デフォルト値の true が考慮されます。
以下に示す例を見てください。
<input value="@name" @onkeydown="KeyDownHandler" @onkeydown:preventDefault />
@code {
private string name { get; set; }
private void KeyDownHandler(KeyboardEventArgs e) {
// do something
}
}
ブール属性はプロパティにバインドできるため、ユーザーの要件に基づいてイベントの伝播を制御できます。
以下に示す例を見てください。
<input @onkeydown="KeyDownHandler" @onkeydown:preventDefault="shouldPreventDefault" />
@code {
private bool shouldPreventDefault = true;
}
イベントの伝播を停止する
HTML 要素が親要素にイベントを伝達することがあります。
Blazor、@on{DOM EVENT}:stopPropagation ディレクティブ属性を使用してイベントの伝播を停止できます。この属性は、引数としてブール値を受け入れます。引数を指定しない場合は、デフォルト値の true が考慮されます。
以下に示す例を見てください。
<button @onclick:stopPropagation>Click</button>
ブール属性はプロパティにバインドできるため、ユーザーの要件に基づいてイベントの伝播を制御できます。
<button @onclick:stopPropagation="shouldStopPropagation">Click</button>
@code {
private bool shouldStopPropagation = true;
}
ルーティング&ナビゲーション
App.razor ファイルで使用される Router コンポーネントは、Blazorアプリケーションのコンポーネントへのルーティングを可能にします。
Blazorアプリケーションを作成すると、App.razorファイルには以下に示すコードが含まれます。
<Router AppAssembly="@typeof(App).Assembly >
<Found Context="routeData" >
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" / >
<FocusOnNavigate RouteData="@routeData" Selector="h1" / >
</Found>
<NotFound>
<PageTitle>NotFound</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert"> Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
Router コンポーネントは、現在のナビゲーション状態に対応するルートデータを提供するために使用されます。FocusOnNavigate コンポーネントは、ユーザーが 1 つのコンポーネントから別のコンポーネントに移動するときに、CSS セレクタに一致する要素にフォーカスを設定するために使用されます。これにより、スクリーンリーダーと互換性のあるアクセス可能なルーティングメカニズムを作成できます。
NotFound プロパティは、要求されたルートでデータが見つからない場合にカスタム コンテンツを表示するために使用されます。
@page ディレクティブを使用して、Razorコンポーネントのルートを定義できます。また、1つのコンポーネントに対して、複数であるが異なる@pageディレクティブを使用することもできます。
以下に示す例を見てください。
@page "/route1"
@page "/home/route1"
<h1>This component is accessible via multiple routes.</h1>
2つの異なるコンポーネントに同じルートを設定することはできません。これを行うと、ランタイムエラーが発生します。
ルート パラメーター
同じ名前でコンポーネントパラメータを設定するために使用できるルートパラメータを定義できます。ルートには複数のパラメーターを含めることができます。
以下に示す例を見てください。
@page "/home/{Name}/{Message}"
<h1>Hello @Name</h1>
<h3>@Message</h3>
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public string Message { get; set; }
}
コンポーネントのルート パラメーター プロパティは、public として定義する必要があります。他のアクセス修飾子を使用すると、コンパイル時にエラーが発生します。
ルートパラメータ名は大文字と小文字を区別しないため、以下に示すようにルートパラメータを使用できます。
@page "/home/{name}/{message}"
<h1>Hello @NAME</h1>
<h3>@MESSAGE</h3>
@code {
[Parameter]
public string NAME { get; set; }
[Parameter]
public string MESSAGE { get; set; }
}
Blazorは、オプションのルート パラメーターもサポートしています。ルート パラメータをオプションとしてマークするには、サフィックスに ?記号。
以下に示す例を見てください。
@page "/home/{name}/{message?}"
<h1>Hello @Name</h1>
<h3>@Message</h3>
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public string Message { get; set; }
}
複数のオプションパラメータを持つことができます。
以下のルートが有効です。
@page "/home/{name}/{message?}/{text?}"
オプション以外のパラメーターは、オプションパラメーターの後に表示することはできません。オプション以外のパラメーターをオプションパラメーターの後に追加すると、ランタイムエラーが発生します。
次のルートは無効です。
@page "/home/{name?}/{message}"
ルート制約
ルート制約を使用して、ルート上での型マッチングを強制できます。
以下に示す例を見てください。
@page "/home/{name}/{userID:int}/{isAdmin:bool}"
<h1>Hello @Name</h1>
<h3>User ID: @userID</h3>
<h3>isAdmin: @isAdmin</h3>
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public int userID { get; set; }
[Parameter]
public Boolean isAdmin { get; set; }
}
このコンポーネントのルートは、次の条件が満たされている場合に一致します。
- ルートには、name パラメーターの値が必要です。
- ルートには userID パラメータの値が必要であり、int 型である必要があります。
- ルートには isAdmin パラメータの値が必要であり、bool 型である必要があります。
このパターンに一致するルートの例は、"/home/John/1234/true" です。
オプションのパラメーターでルート制約を使用することもできます。
例
@page "/home/{name}/{userID:int}/{isAdmin:bool?}"
NavigationManager
NavigationManagerクラスを使用して、C#コードを介してナビゲーションを処理できます。このクラスは、コンポーネントのルートをパラメーターとして受け取り、ユーザーを 1 つのコンポーネントから別のコンポーネントにリダイレクトする NavigateTo メソッドを提供します。
例の助けを借りてこれを理解しましょう。
以下に示すように、基本クラスをRouting.razor.cs作成しました。
using Microsoft.AspNetCore.Components;
namespace BlazorWasmDemo.Client.Pages;
public class RoutingBase : ComponentBase { [Inject] public NavigationManager NavigationManager { get; set; }
[Parameter] public string Name { get; set; }
protected void NavigateAway() { NavigationManager.NavigateTo("parent/1234"); } }
Routing.razor コンポーネントに次のコードを追加します。
@page "/home/{name}"
@inherits RoutingBase
<h1>Hello @Name</h1>
<button @onclick="NavigateAway" >Navigate away</button>
ボタンをクリックするだけで NavigateAway メソッドを呼び出します。ユーザーをルート "/parent/1234" にリダイレクトします。
NavigateTo メソッドは、省略可能なブール パラメーター forceLoad を受け入れます。このパラメータに true 値を渡すと、ブラウザはサーバーから新しいページを再読み込みします。
キャッチオールのルート パラメーター
キャッチオールのルート パラメータは、ルーティング パラメータが明示的に定義されていない場合に、さまざまなルートを処理するために使用できます。
以下に示すコンポーネントの例を見てください。
@page "/home/{*routeParams}"
@code {
[Parameter]
public string? RouteParams { get; set; }
}
このコンポーネントでは、次のルートが有効です。
- /home/John
- /home/123
- /home/John/123/345/USA/true
キャッチオールのルート パラメータは、次の基準に従う必要があります。
- 同じ名前の対応するコンポーネントパラメータが必要です。名前は大文字と小文字を区別しません。
- 文字列型である必要があります。それらにルート制約を使用することはできません。
- URL の末尾に記述する必要があります。
NavLink コンポーネント
ナビゲーションリンクを作成する際に、HTML の <a> 属性の代わりに NavLink コンポーネントを使用できます。これは、現在の URL が href プロパティと一致するかどうかに基づいて、アクティブな CSS クラスを切り替えます。これにより、ユーザーは、使用可能なすべてのナビゲーション リンクの中でどのページがアクティブであるかを理解できます。
例
<NavLink class="nav-link" href="" Match="NavLinkMatch.All" >
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
NavLinkコンポーネントのMatch属性には、次の2つの値を指定できます。
- NavLinkMatch.All: NavLink は、現在の URL 全体と一致する場合にのみアクティブにする必要があります
- NavLinkMatch.Prefix: NavLink は、現在の URL の任意のプレフィックスと一致する場合にのみアクティブにする必要があります。これがデフォルト値です。
クエリ文字列
[SupplyParameterFromQuery] 属性と [Parameter] 属性を使用して、ルート クエリ文字列を介してコンポーネント パラメーターを提供できるように指定できます。
@page "/movie"
<p>@Name</p>
<p>@Genre</p>
@code {
[Parameter]
[SupplyParameterFromQuery]
public string? Name { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public string? Genre { get; set; }
}
このコンポーネントの有効なルートは "/movie?name=avatar&genre=science%20fiction" で、Name プロパティを使用してクエリ パラメーターの名前を指定できます。
例
[Parameter]
[SupplyParameterFromQuery(Name="Category")]
public string? Genre { get; set; }
この場合、有効なルートは「/movie?name=avatar&category=science%20fiction」となります。
コンポーネントのクエリパラメータは、次のデータ型をサポートします。
- bool型
- DateTime型
- decimal型
- double型
- float型
- Guid型
- int型
- long型
- string型
NavigationManager クラスの GetUriWithQueryParameter メソッドを使用して、現在の URL から 1 つ以上のクエリ パラメーターを追加、更新、または削除できます。
このメソッドの構文は GetUriWithQueryParameter("{NAME}", {VALUE}) で、{NAME} はクエリ パラメータの名前のプレースホルダーで、{VALUE} はクエリ パラメーターの値のプレースホルダーです。このメソッドは文字列値を返します。
クエリ パラメーターが現在の URI に既に存在する場合、このメソッドは値を更新します。クエリ パラメーターが現在の URI に存在しない場合、このメソッドは指定された値で新しいパラメーターを追加します。
例
@page "/movie"
@inject NavigationManager Navigation
<p>@Name</p>
<p>@Genre</p>
<button @onclick="UpdateCurrentURI">Update URI</button>
<p>NewURI: @NewURI</p>
<button @onclick="NavigateToNewURI">Go To New URI</button>
@code {
string NewURI { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public string? Name { get; set; }
[Parameter]
[SupplyParameterFromQuery(Name = "Category")]
public string? Genre { get; set; }
void UpdateCurrentURI() {
NewURI = Navigation.GetUriWithQueryParameter("name", "Top Gun");
}
void NavigateToNewURI() {
Navigation.NavigateTo(NewURI);
}
}
クエリパラメータの値 "name" は、ボタンをクリックすると更新されます。
新しいクエリパラメータをURIに追加する場合は、次のようにコードを更新できます。
NewURI = Navigation.GetUriWithQueryParameter("language", "English");
URIから既存のクエリパラメータを削除する場合は、以下に示すように値をnullに設定できます。
NewURI = Navigation.GetUriWithQueryParameter("name", (string?)null);
GetUriWithQueryParameters メソッドを使用して、URI から複数のパラメーターを同時に追加、更新、および削除できます。
以下に示す例を見てください。
NewURI = Navigation.GetUriWithQueryParameters(new Dictionary<string, object?>
{
["name"] = "Top Gun",
["category"] = "Action",
["language"] = "English",
});
これにより、既存のクエリ パラメータ name & category が更新され、新しいクエリ パラメータ language が追加され、値が English に設定されます。
Blazorレイアウト
レイアウトは、ナビゲーションメニュー、ヘッダー、フッターなどの複数のコンポーネントに共通するUI機能を含むBlazorコンポーネントです。既定のアプリ レイアウトは、App.razor ファイル内の Router コンポーネントで定義されます。
レイアウトを使用できるのは、@pageディレクティブを持つルーティング可能なRazorコンポーネントのみです。既定のアプリ レイアウトは、App.razor ファイル内の Router コンポーネントで定義されます。
@layout ディレクティブを使用して、@page ディレクティブを持つルーティング可能なコンポーネントのレイアウトを指定できます。コンポーネントでレイアウトを直接指定すると、Router コンポーネントで設定されたデフォルトのアプリケーションレイアウトが上書きされます。
以下に示す例を見てください。
@layout CustomLayout
@page "/layout-demo"
<h1>Custom layout demo.</h1>
Blazorは、レイアウトのネストをサポートしています。コンポーネントはレイアウトを参照でき、レイアウトは別のレイアウトを参照します。これは、マルチレベルのメニュー構造を作成するのに役立ちます。
カスタムレイアウトコンポーネントの作成
コンポーネントをレイアウト コンポーネントとして機能させるには、次の 2 つの条件を満たす必要があります。
- これは、LayoutComponentBase クラスから継承する必要があります。このクラスは、レイアウト内のコンテンツをレンダリングするために使用される Body プロパティを定義します。
- 本文の内容をレンダリングする場所を指定する場所を定義する必要があります。これは、Razor構文@Bodyを使用して行われます。
以下に示す例を見てください。
@inherits LayoutComponentBase
<header>
<h1>Welcome to Blazor tutorial</h1>
</header>
@Body
<footer>
<h1>All rights reserved</h1>
</footer>
依存関係の挿入
依存関係注入(DI)は、クラスとその依存関係の間で制御の反転(IoC)を実現するのに役立つソフトウェア設計パターンです。
フレームワークに登録されたサービスをBlazorコンポーネントに直接挿入できます。カスタムサービスは、DI経由で利用できるようにするために、Blazorアプリに登録する必要があります。
サービスライフタイム
Blazorサービスは、次の 3 つのライフタイムで構成できます。
- Singleton(シングルトン):すべてのコンポーネントで共有されるサービスの 1 つのインスタンスを作成します。
- Transient(一時的):コンポーネントがサービスを要求するたびに、サービスの新しいインスタンスを作成します。
- Scoped(スコープ):これにより、Web 要求ごとにサービスのインスタンスが 1 つ作成されます。
- Blazor WebAssembly アプリは、スコープ付きライフタイムをサポートしていません。スコープ登録されたサービスは、Blazor WebAssembly アプリのシングルトン サービスのように動作します。
- Blazor Server アプリは、HTTP 要求間でスコープ付き有効期間をサポートしますが、クライアント側で読み込まれるコンポーネント間の SignalR 接続メッセージ間ではサポートしません。
デフォルトのBlazorサービス
次の表に示すサービスは、Blazorアプリで頻繁に使用されます。
サービス | Blazor Wasmライフタイム | Blazorサーバーのライフタイム | 形容 |
---|---|---|---|
HttpClient | スコープ | スコープ | HTTP 要求とリソース URL からの応答を処理するためのメソッドを提供します。 |
IJSRuntime | シングルトン | スコープ | JavaScript 呼び出しがディスパッチされる JavaScript ランタイムのインスタンスを表します。 |
NavigationManager | シングルトン | スコープ | URI ナビゲーションのクエリと管理のためのヘルパー クラスを提供します。 |
Blazor WASM アプリにサービスを追加する
Program.csファイルを使用して、Blazor WasmアプリとBlazor Serverアプリの両方のカスタムサービスを登録できます。
Blazor Wasm アプリの Program.cs ファイルのコード サンプルを確認します。
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
Blazor Server アプリの Program.cs ファイルのコード サンプルを確認します。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
app.UseRouting();
app.Run();
Blazorコンポーネントへのサービスの挿入
次の 2 つの方法を使用して、サービスをコンポーネントに挿入できます。
- 基本クラスの [Inject] 属性を使用します。
- コンポーネントで @inject ディレクティブを使用する。
1つのコンポーネントに複数のサービスを挿入できます。
Razorコンポーネントについて、以下に示す例を見てください。
@page "/movie"
@inject NavigationManager Navigation
<button @onclick="NavigateToPage">Go To Page</button>
@code {
void NavigateToPage()
{
Navigation.NavigateTo("/home");
}
}
基本クラスについて、以下に示す例を見てください。
using Microsoft.AspNetCore.Components;
namespace BlazorWasmDemo.Client.Pages
{ public class RoutingBase : ComponentBase { [Inject] public NavigationManager NavigationManager { get; set; } = default!;
[Inject] HttpClient Http { get; set; } = default!;} }
挿入されたサービスは、コンポーネントが初期化されると使用可能になることが期待されるため、null を許す演算子 (default!) を使用して既定のリテラルを割り当てました。null 以外のデフォルト値を割り当てない場合、コンパイラは "コンストラクターを終了するときに null 値以外の値を含まないプロパティが含まれている必要があります" という警告メッセージを表示します。または、.NET SDK バージョン 7 以降では、C#11 から追加された "required" 修飾子を使用して、null を許容する演算子に頼らずに次の記述を行うことができます。
[Inject] public required NavigationManager NavigationManager { get; set; }
Blazorサービスで依存関係の挿入を使用する
コンストラクタインジェクションを使用して、サービスを別のサービスに注入できます。[Inject] 属性または @inject ディレクティブは、サービス クラスでは使用できません。
以下に示す例を見てください。
public class MyCustomService
{ private readonly HttpClient _httpClient;private readonly HttpClient _httpClient; public MyCustomService(HttpClient httpClient, NavigationManager navigationManager) { _httpClient = httpClient; _navigationManager = navigationManager; } }
JavaScript 相互運用
JavaScript との相互運用性 (別名 JavaScript 相互運用機能) は、.NET メソッドから JavaScript 関数を呼び出す機能、および JavaScript 関数から .NET メソッドを呼び出す機能として定義されます。
.NET メソッドから JavaScript 関数を呼び出す
IJSRuntime 抽象層を使用して、.NET から JavaScript 関数を呼び出すことができます。
IJSRuntime インターフェイスには、次の 2 つの方法があります。
- InvokeAsync: これは、任意の値またはオブジェクト (Promise を含む) を返す JavaScript 関数を呼び出すために使用されます。
- InvokeVoidAsync: void または undefined を返す JavaScript 関数を呼び出すために使用されます。
カスタムJavaScriptコードをBlazor WebAssemblyアプリの wwwroot/index.html に追加できます。カスタム JavaScript コードをBlazor WebAssembly アプリの Pages/_Host.cshtml に追加できます。
例を挙げてこれを理解しましょう。
<script>
window.getArraySum = (numberArray) => {
return numberArray.reduce((a, b) => a + b, 0);
}
</script>
getArraySum 関数は、配列をパラメーターとして受け取り、配列のすべての要素の合計を返します。
コンポーネント JSDemoBase.razor を作成し、次のコードを基本クラスのJSDemoBase.razor.csに追加します。
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace BlazorWasmDemo.Client.Pages;
public class JSDemoBase : ComponentBase
{ [Inject] Protected IJSRuntime JSRuntime { get; set; } = default!;
protected int sumOfArray = 0;
private int[] arrayItems = new int[] { 2, 4, 6, 8, 10 };
protected async Task GetSumOfArray(){ sumOfArray = await JSRuntime.InvokeAsync<int>("getArraySum", arrayItems); } }
InvokeAsync メソッドを使用して JS 関数を呼び出します。JS 関数は合計を返し、整数変数 sumOfArray に割り当てられます。
この GetSumOfArray メソッドは、次に示すように、ボタンのクリックで呼び出すことができます。
@page "/calljsmethod"
@inherits JSDemoBase
<button @onclick="GetSumOfArray">Get Array Sum</button>
<p>The sum of array elements is : @sumOfArray</p>
JavaScript の組み込みメソッドを呼び出す場合は、次のコードを使用できます。
protected async Task ShowAlert()
{ await JSRuntime.InvokeVoidAsync("alert", "I am invoked from .NET code"); }
protected async Task ShowArrayItems()
{ await JSRuntime.InvokeVoidAsync("console.table", arrayItems); }
アラート関数を呼び出し、文字列パラメータを渡しました。ShowArrayItems メソッドは、JavaScript の console.table 関数を呼び出し、表示される arrayItems を入力として渡します。
HTML 要素への参照をキャプチャする
ElementReference 構造体を使用して、コンポーネント内の HTML 要素への参照をキャプチャできます。これは、レンダリングされた要素への参照を表すために使用されます。
コンポーネント内の HTML 要素への参照をキャプチャするには、HTML 要素に [@ref] 属性を追加する必要があります。また、名前が @ref 属性の値と一致する ElementReference 型のフィールドを定義します。
JS 相互運用機能を介して ElementReference を JS コードに渡すことができます。JSコードは、DOM操作に使用できるHTMLElementインスタンスを受け取ります。
例を挙げてこれを理解しましょう。
次の JS コードを追加します。
<script>
window.showValue = (element) => {
alert('Your name is :' + element.value);
}
</script>
この関数は、HTML 要素の参照を受け取り、アラートボックスに値を表示します。
この関数を呼び出すために、基本クラスに次のコードを追加できます。
protected ElementReference name;
protected async Task ShowName()
{ await JSRuntime.InvokeVoidAsync("showValue", name); }
次のコードに示すように、HTML 要素の @ref 属性を使用して ElementReference インスタンスをキャプチャできます。
<button class="btn btn-primary" @onclick="ShowName">Show Name</button>
<input type="text" @ref="name" class="form-control" placeholder="Enter your name" />
JavaScript 関数から静的 .NET メソッドを呼び出す
DotNet.invokeMethod または DotNet.invokeMethodAsync 関数を使用して、JS から静的 .NET メソッドを呼び出すことができます。
.NET メソッドは、次の条件を満たす必要があります。
- public および static として宣言する必要があります。
- [JSInvokable] 属性で修飾する必要があります。
静的メソッドの識別子、C# メソッドを含むアセンブリの名前、および必要な引数を渡すことができます。
関数の構文は次のとおりです - DotNet.invokeMethodAsync('{アセンブリ名}', '{.NET メソッド名}', {引数});
ここで、
- {アセンブリ名} は、アプリケーション アセンブリ名のプレースホルダーです。
- {.NET メソッド名} は、呼び出される .NET メソッドのプレースホルダです。
- {引数} は、呼び出される .Net メソッドに必要な引数のプレースホルダーです。これはオプションのパラメータです。
例を挙げてこれを理解しましょう。
JSDemoBase.razor.cs ファイルに次のコードを追加します。
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace BlazorTutorial.Client.Pages;
public class JSDemoBase: ComponentBase
{ [Inject] protected IJSRuntime JSRuntime { get; set; } = default!;
protected void InvokeJSMethod() { JSRuntime.InvokeVoidAsync("printMessageToConsole"); }
[JSInvokable] public static Task<string> PrintMessage() { return Task.FromResult("I am invoked from JavaScript."); }}
InvokeJSMethod は、JS 関数 printMessageToConsole を呼び出します。PrintMessage メソッドには [JSInvokable] 属性があります。このメソッドは、public および static として宣言されます。これにより、JS関数printMessageToConsoleがPrintMessageメソッドを呼び出すことができるようになります。
次に示すように、JSDemoBase.razor ファイルにボタンを追加します。
<button @onclick="InvokeJSMethod">Invoke static .NET method</button>
次の JS コードを追加します。
<script>
window.printMessageToConsole = () => {
DotNet.invokeMethodAsync(BlazorTutorial.Client', 'PrintMessage')
.then(data => {
console.log(data);
});
}
</script>
JS 関数 printMessageToConsole を作成しました。DotNet.invokeMethodAsync 関数を使用して、C# メソッド PrintMessage を呼び出します。アセンブリの名前を BlazorTutorial.Client として渡しました。
コンポーネントインスタンスメソッドの呼び出し
次の手順を使用して、Blazorコンポーネントの .NET インスタンス メソッドを呼び出すことができます。
- DotNetObjectReference.Create を使用して JavaScript 関数に渡すことができる .NET オブジェクト参照を生成します。
- .NET オブジェクトの invokeMethod メソッドまたは invokeMethodAsync メソッドを使用して、コンポーネントへのインスタンス メソッド呼び出しを行います。
- コンポーネントが破棄されるときに、.NET オブジェクト参照も破棄されることを確認します。
例を挙げてこれを理解しましょう。
次の JS コードを追加します。
function displayMessageCallerJS(objectRef, value) {
objectRef.invokeMethodAsync('DisplayMessage', value);
}
objectRef と value という名前の 2 つのパラメーターを受け入れる関数 displayMessageCallerJS を追加しました。次に、この関数は、objectRef が参照しているコンポーネント オブジェクトの DisplayMessage メソッドを呼び出し、値を引数として渡します。
JSDemoBase.razor.csファイルに次のコードを追加します。
public class JSDemoBase : ComponentBase, IDisposable
{
private DotnetObjectReference<JSDemoBase>? objectRef;
protected string message = "Click the button.";
protected override void OnInitialized()
{
objectRef = DotNetObjectReference.Create(this);
}
[JSInvokable]
public void DisplayMessage(string value)
{
message = value;
StateHasChanged();
}
public void Dispose()
{
objectRef?.Dispose();
}
}
.NET オブジェクトの参照を表す DotNetObjectReference<JSDemoBase> 型のフィールド変数 objectRef を宣言しました。OnInitialized ライフサイクル メソッド内では、DotNetObjectReference.Create 静的メソッドを使用してこのコンポーネント自体の参照を作成し、それを objectRef フィールドに割り当てます。
InvokeDisplayMessageCallerJS メソッドは、文字列パラメーターを受け入れます。次に、このメソッドは JS 関数 displayMessageCallerJS を呼び出し、このコンポーネントを参照する .NET オブジェクト参照フィールドを最初の引数として渡し、string パラメーターを 2 番目の引数として渡します。
[JSInvokable] 属性を持ち、文字列パラメーターを受け入れるパブリック インスタンス メソッド DisplayMessage を作成しました。このインスタンスメソッドは、JS 関数 displayMessageCallerJS から呼び出されます。パラメータ値をメッセージフィールドに割り当ててから、StateHasChanged() メソッドを呼び出して、状態の変更についてコンポーネントに通知します。
最後に、IDisposable インターフェイスを実装して、このコンポーネントが破棄されるときに、コンポーネント自体を参照する .NET オブジェクト参照も破棄されるようにします。具体的には、このコンポーネントの Dispose メソッドで .NET オブジェクト参照の Dispose メソッドを呼び出しました。
次に示すように、JSDemoBase.razor ファイルにボタンを追加します。
<button @onclick="@(()=>InvokeDisplayMessageCallerJS("The Button is clicked"))">Call JS Method</button>
<br />
<p >@message</p>
ボタンをクリックすると、InvokeDisplayMessageCallerJSメソッドが呼び出され、パラメータとして文字列値が渡されます。メッセージの更新された値が画面に表示されます。
読み続けて
続きを読むにはフォームに記入してください。