MAUI Blazor

以前、Blazor Hybridの例で、Windows FormsとBlazorを試してみたが、今回はMAUIで試してみた。

MAUIの場合も、Windows Formsと同様にMAUI~Blazor間の連携が可能。

共有する、Singletonインスタンスを以下のような感じで作成し、MauiProgram.cs内でサービス登録することで、相互で同じインスタンスを共有できる。

namespace MAUIBlApp;

public interface IHostIF {
    /// <summary>
    /// 共有データ
    /// </summary>
    /// <value>カウント値</value>
    public int Count { get; set; }
    /// <summary>
    /// イベントハンドラ
    /// </summary>
    public event EventHandler ComponentEvent;
    /// <summary>
    /// クライアント側からイベント発生
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public void FireClientEvent(object sender, EventArgs e);
    /// <summary>
    /// ホスト側からクライアントの画面更新
    /// </summary>
    /// <value></value>
    public Action RefreshClient { get; set; }
}
/// <summary>
/// IHostIFの実装
/// </summary>
public class HostInterface : IHostIF {
    public int Count { get; set; } = 0;
    public event EventHandler ComponentEvent = null!;
    public void FireClientEvent(object sender, EventArgs e) {
        ComponentEvent?.Invoke(sender,e);
    }
    public Action RefreshClient {get; set; } = null!;
}
using Microsoft.Extensions.Logging;

namespace MAUIBlApp;

public static class MauiProgram
{
	public static MauiApp CreateMauiApp()
	{
		var builder = MauiApp.CreateBuilder();
		builder
			.UseMauiApp<App>()
			.ConfigureFonts(fonts =>
			{
				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
			});

		HostInterface hst = new HostInterface();
		builder.Services.AddSingleton<IHostIF>(hst);
		builder.Services.AddMauiBlazorWebView();

・・・
namespace MAUIBlApp;

public partial class App : Application
{
	public App(IHostIF hif)
	{
		InitializeComponent();
		// MainPageのロード(IHostIF(Singleton)インスタンスを渡す)
		MainPage = new MainPage(hif);
	}
}
public partial class MainPage : ContentPage
{
	private readonly IHostIF _hostif;
	/// <summary>
	/// コンストラクタ(IHostIFのインスタンスを取得)
	/// </summary>
	/// <param name="hostif"></param>
	public MainPage(IHostIF hostif)
	{
		InitializeComponent();
		_hostif = hostif;
		// Client(Blazor Component)イベントハンドラ設定
		_hostif.ComponentEvent += OnClientEvent;
		lblNumber.Text = _hostif.Count.ToString();
	}
	/// <summary>
	/// ボタンクリック時処理
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="e"></param>
	public void OnBtnClick(object sender, EventArgs e) {
		// インターフェースのカウントアップ
		_hostif.Count++;
		lblNumber.Text = _hostif.Count.ToString();
		// Client(Blazor Component)のリフレッシュ
		if (_hostif.RefreshClient != null) {
			_hostif.RefreshClient();
		}
	}
	/// <summary>
	/// Client(Blazor Component)イベントハンドラ
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="e"></param>
	public void OnClientEvent(object? sender, EventArgs e) {
		lblNumber.Text = _hostif.Count.ToString();
	}
}
@page "/"

@inject IHostIF HostInterface

<h2>Counter</h2>

<p role="status">Current count:
@if (Numbers != null && Numbers.Count != 0) {
    foreach(var v in Numbers) {
        string imgname = $"/images/number_{v}.png";
        <img src="@imgname" style="width:42px;height:49px"/>
    }
}
</p>
<br/>

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

@code {

    /// <summary>
    /// カウンタのイメージIndex
    /// </summary>
    /// <returns></returns>
    protected List<int> Numbers = new () {0};

    /// <summary>
    /// Initialize
    /// </summary>
    protected override void OnInitialized() {
        // コンポーネント側を外部からリフレッシュするActionの設定
        HostInterface.RefreshClient = async () => await InvokeAsync(()=>{CreateNumberImages();StateHasChanged();});
    }
    /// <summary>
    /// ボタンイベント
    /// </summary>
    private void IncrementCount()
    {
        // Interfaceのカウントをインクリメント
        HostInterface.Count++;
        // カウンタ⇒イメージ番号の作成
        CreateNumberImages();
        // ホストに通知
        HostInterface.FireClientEvent(this,new EventArgs());
    }
    /// <summary>
    /// イメージ番号の生成
    /// </summary>
    private void CreateNumberImages() {
        Numbers = new();
        string s = HostInterface.Count.ToString();
        for(int i=0;i < s.Length; i++) {
            Numbers.Add(Convert.ToInt32(s[i].ToString()));
        }
    }
}

以下のように、MAUI側からでもBlazorコンポーネント側からでも同じインスタンスを参照していることが分かる。

最初、MainPageの呼出でコンパイルエラーが出ていて悩んだが、よくよくエラーを見ると、MainPage.xaml.csでは無く、App.xaml.csでMainPageインスタンスを作成するときに、インターフェイスインスタンスを渡していないエラーだった。

Appのコンストラクタにインターフェイスインスタンスをパラメータで指定することにより、サービス登録されたSingletonインスタンスを取得できるので、これをMainPage作成時のパラメータとして渡すことで解決できた。

※MAUIをVS Codeで作成するなら「.NET MAUI拡張」を入れておくと便利。

takezou について

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

コメントを残す

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

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