Blazor Hybrid-コンポーネントとホスト間I/F

以前、Blazor Hybridについて簡単に説明したが、razorコンポーネントとホスト間のやりとりについて、もう少し詳しく説明してみる。(記事のコメントにも少々文書で書いたが、今回は簡単な実例で説明してみる。)

まず、ホスト,コンポーネント双方で使用する、インターフェースとその実装を以下のような感じで作成する。

public delegate void OnClientEvent(object sender, EventArgs e);
public interface IHostInterface {
    public string Message { get; set; }
    public int Count { get; set; }
    /// <summary>
    /// コンポーネントのリフレッシュ等を行なうメソッド
    /// (コンポーネント側でセットする)
    /// </summary>
    /// <value></value>
    public Action ComponentRefresh { get; set; }
    /// <summary>
    /// コンポーネントでイベントが発生した時に呼ばれるホスト側イベントハンドラ
    /// </summary>
    public event OnClientEvent ComponentEvent;
    /// <summary>
    /// コンポーネント側からイベントを発生させるメソッド
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public void ExecClientEvent(object sender, EventArgs e);
}
public class HostInterface : IHostInterface {
    public string Message { get; set; } = null!;
    public int Count { get; set; } = 0;
    public Action ComponentRefresh { get; set; } = null!;
    public event OnClientEvent ComponentEvent = null!;
    public void ExecClientEvent(object sender, EventArgs e) {
        ComponentEvent.Invoke(sender,e);
    }
}

コンポーネント側では、このインターフェースを@injectでSingletonオブジェクトとして、使用できるようにする。

下記の例では、インターフェイス中のCounterプロパティをホストとの共有データとして使用し、ホスト側のトリガで、コンポーネントの更新が行えるよう、ComponentRefreshでStateHasChangedメソッドを呼び出せるようにしている。

また、コンポーネント側のイベントを、ホストにも知らせることができるよう、イベント発生時に、ホスト側のイベントハンドラを呼び出している。

@inject IHostInterface HostIF

<h1>Counter</h1>

<p>Current count: @HostIF.Count</p>

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

@code {
    protected override void OnInitialized() {
        // Componentの再描画メソッドを設定
        HostIF.ComponentRefresh = (Action)(()=>StateHasChanged());
    } 

    private void IncrementCount() {
        // カウントアップした後、ホスト側へイベント通知
        HostIF.Count++;
        HostIF.ExecClientEvent(this,new EventArgs());
    }
}

ホスト側では、コンストラクタで、ComponentEventにハンドラを設定することにより、コンポーネントで状態変更が有った場合の処理を定義できる。

private HostInterface HostIF;
public Form1()
{
    InitializeComponent();
    var services = new ServiceCollection();
    services.AddWindowsFormsBlazorWebView();
    // Singletonオブジェクトの作成
    HostIF = new HostInterface();
    // コンポーネントから呼び出されるイベントハンドラ
    HostIF.ComponentEvent += On_ClientEvent;
    // Singletonオブジェクトをコンポーネントサービスに追加
    services.AddSingleton<IHostInterface>(HostIF);
    blView.HostPage = @"wwwroot\index.html";
    blView.Services = services.BuildServiceProvider();
    blView.RootComponents.Add<Counter>("#app");
}
/// <summary>
/// インクリメントボタンクリックイベントハンドラ
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void On_btnIncrement_Click(object sender, EventArgs e) {
    // Singletonのカウンタをインクリメント
    HostIF.Count++;
    lblMessage.Text = $"カウント:{HostIF.Count}";
    // コンポーネント表示を更新
    HostIF.ComponentRefresh();
}
/// <summary>
/// コンポーネントイベントハンドラ
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void On_ClientEvent(object sender, EventArgs e) {
    // ホストの表示を更新
    lblMessage.Text = $"カウント:{HostIF.Count}";
}

実行すると以下のように、ホストとコンポーネント間の同期が取れていることが分かる。

何かに使えるかも知れないので、メモ。

takezou について

ソフトウェア開発会社(ITと言う言葉は大嫌い)で働く、元技術者。 未だに、社内システム位は作ってますが・・・ プログラミング言語はC#が好き。 好きなことだけ拾って投稿しているので、内容にはあまり期待しないでねw
カテゴリー: .NET, Blazor, C#, 技術系 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください