1. Masa Blazor とは
これまでに Masa Blazor とは何か、および Masa Blazor の使用方法について紹介してきました。まだ Masa Blazor に詳しくない方は、以前の記事「初識 Masa Blazor」をご覧ください。今回は、MAUI で Masa Blazor を使用する方法を探ります。まず、MAUI とは何かを理解しましょう。
2. MAUI とは
.NET MAUI の正式名称は .NET Multi-platform App UI で、その名の通り .NET マルチプラットフォーム アプリ UI であり、クロスプラットフォームフレームワーク で、Xamarin.Forms の進化版です。C# と XAML を使用してネイティブのモバイルおよびデスクトップアプリケーションを作成しますが、ここでの XAML は RazorView に置き換えることもできます。.NET MAUI を使用すると、Android、iOS、macOS、Windows、Linux(コミュニティサポート)向けのアプリケーションを単一の共有コードベースから開発でき、1つのコードで複数のプラットフォームで動作します。

2.1 MAUI の利点:
XAML と C# の単一の共有コードベースから、クロスプラットフォームの Visual Studio を記述できます。
クロスプラットフォームで UI レイアウトとデザインを共有できます。
クロスプラットフォームでコード、テスト、ビジネスロジックを共有できます。
もう1つの利点は、
Razorコンポーネントをフレームワーク間で再利用できることです。これはRazorクラスライブラリ (RCL) として実装でき、Blazor ServerおよびWebAssemblyと共有できます。これにより、コードの再利用を最大限に高め、単一のコードベースからモバイル、デスクトップ、Webソリューションを生成できます。
今回は 実践に重点を置く ため、概念的な説明はあまり行いません。MAUI についてさらに詳しく知りたい方は、公式ドキュメント「.NET MAUI とは」をご覧ください。この記事では、MAUI+Masa Blazor を使用して、モバイルでよく見られるタイムラインページを作成し、さらにテーマカラーを切り替える小さな機能を追加します。完成イメージは以下の通りです。


それでは、段階的に実装していきましょう。まず、必要な環境を準備します。
注:記事のサンプルデモ環境は(MAUI 6.0.200-preview.14.5 + Masa.Blazor 0.3.0)です。
3. MAUI 環境の準備
- まず、
最新バージョンの Visual Studioがインストールされていること、およびMobile development with .NETワークロードがインストールされていることを確認します。

- ハードウェアアクセラレーションを有効にして、Android エミュレーターのパフォーマンスを最大化します。
Hyper-VまたはHAXMアクセラレーションを有効にできます。ここでは最初の方法のみ紹介します。
- Windows の検索ボックスに「Windows の機能」と入力し、検索結果から「Windows の機能の有効化または無効化」を選択します。 「Windows の機能」ダイアログで、「Hyper-V」と「Windows ハイパーバイザー プラットフォーム」を有効にします。

これらの変更を行った後、コンピューターを再起動します。
Android Device Manager で作成する仮想デバイスは、x86 64 または x86 ベースのシステムイメージを使用してください。Arm ベースのシステムイメージを使用すると、仮想デバイスが高速化されず、動作が遅くなります。Hyper-V を有効にすると、高速化された Android エミュレーターを実行できます。HAXM アクセラレーションと詳細設定については、「Android エミュレーターの使用方法」および「ハードウェアアクセラレーションの有効化」を参照してください。
4. MAUI アプリの作成と Masa Blazor の導入
- プロジェクトの作成で
.NET MAUI Blazor Appを選択します。これにより、Blazor Viewを使用して UI インターフェースを記述できるようになります。

- NuGet で
Masa.Blazorをインストールし、MauiProgram.csファイルで関連サービスを登録します。

builder.Services.AddMasaBlazor();
CreateMauiApp()メソッドの簡単な説明:スタートアップメソッド内で、RegisterBlazorMauiWebView()ビルダーオブジェクトの拡張メソッドを呼び出し、BlazorWebView自体をbuilder.Servicesプロパティを使用して DI コンテナの Services コレクションに追加します。これにより、依存性注入が実行され、出力 HTML をレンダリングするためのプラットフォーム固有のビューが読み込まれます。各プラットフォームには独自の Web エンジンがあるため、BlazorWebView(Viewから継承)コントロールは、Razor コンポーネントを処理し、それに相当する HTML を実行時に生成できます。この HTML は、Web サーバーを介さずにプラットフォームのネイティブ Web エンジンを使用してレンダリングされます。
wwwroot/index.htmlにスタイル、フォント、スクリプトを追加します。

<link href="_content/Masa.Blazor/css/masa-blazor.css" rel="stylesheet" />
<link href="_content/Masa.Blazor/css/masa-extend-blazor.css" rel="stylesheet" />
<link
href="https://cdn.masastack.com/npm/@mdi/font@5.x/css/materialdesignicons.min.css"
rel="stylesheet"
/>
<link
href="https://cdn.masastack.com/npm/materialicons/materialicons.css"
rel="stylesheet"
/>
<link
href="https://cdn.masastack.com/npm/fontawesome/v5.0.13/css/all.css"
rel="stylesheet"
/>
<script src="_content/BlazorComponent/js/blazor-component.js"></script>
<script src="https://cdn.masastack.com/npm/echarts/5.1.1/echarts.min.js"></script>
<!-- echarts のスクリプトファイルは不要であれば読み込まなくても構いません -->
注意:
MAUI プロジェクトでは、Blazor のように
Pages/_Layout.cshtmlではなく、index.htmlにこれらのファイルを追加する必要があります。Masa Blazor 0.3.0 以降では、Microsoft と同じ命名規則(大文字キャメルケース)を採用しており、MASA は Masa に変更されました。0.3.0 以降のバージョンにアップグレードする際は、間違った名前を記述しないように注意してください。そうしないと、スタイルファイルや js ファイルが見つからなくなります。
_Imports.razorファイルでMasa.BlazorおよびBlazorComponent名前空間を参照します。これにより、各ファイルで個別に参照する必要がなくなります。
5. タイムライン機能の実装
まず、レイアウトページ MainLayout.razor でページのおおまかなレイアウトを作成します。上部には Toolbar、下部には下部ナビゲーション、中央には子ページを配置します。
このような一般的なレイアウトページで、ツールバーのメニューをクリックするとテーマカラーを切り替えられるようにします。Masa Blazor を使用して簡単に実装してみましょう。
上部ツールバーでは主に MToolbar コンポーネントと MMenu コンポーネントを使用します。下部ナビゲーションについては、BottomNavigation コンポーネントは公式サイトにはまだなく、今後のバージョンでリリースされる予定ですが、影響は小さいため、代わりに MFooter コンポーネントを使用します。これでレイアウトテンプレートページは完成です。グローバルな色は変数に保存し、MMenu で選択された値で制御します。

Mainlayout.razor の完全なコード:
@inherits LayoutComponentBase
<MApp>
<MToolbar MaxHeight="64" Color="@_color" Dark>
<MAppBarNavIcon></MAppBarNavIcon>
<MSpacer></MSpacer>
Timeline
<MSpacer></MSpacer>
<MMenu Left OffsetY Transition="slide-x-transition" Bottom>
<ActivatorContent>
<MButton Icon @attributes="@context.Attrs">
<MIcon>mdi-dots-vertical</MIcon>
</MButton>
</ActivatorContent>
<ChildContent>
<MList>
@foreach (var item in _colors) {
<MListItem OnClick="()=>{_color = item.Value;}">
<MListItemTitle>@item.Text</MListItemTitle>
</MListItem>
}
</MList>
</ChildContent>
</MMenu>
</MToolbar>
<div style="width:100%; height:100%">
<CascadingValue Value="_color"> @Body </CascadingValue>
</div>
<MFooter Color="#FAFAFA" Elevation="2">
<MRow NoGutters Justify="JustifyTypes.SpaceBetween">
<MCol Style="display:flex; justify-content:center;">
<MButton Color="@_color" Icon Class="my-2 white--text">
<MBadge OverLap Color="error" Content="6">
<ChildContent>
<MIcon>mdi-chat</MIcon>
</ChildContent>
</MBadge>
</MButton>
</MCol>
<MCol Style="display:flex; justify-content:center;">
<MButton Color="@_color" Icon Class="my-2 white--text">
<MIcon>mdi-account-details</MIcon>
</MButton>
</MCol>
<MCol Style="display:flex; justify-content:center;">
<MButton Color="@_color" Icon Class="my-2 white--text">
<MIcon>mdi-compass</MIcon>
</MButton>
</MCol>
</MRow>
</MFooter>
</MApp>
@code{ private string _color = "purple darken-3"; private List<(string Text,
string Value)> _colors = new() { new("pink", "purple darken-1"), new("indigo",
"indigo"), new("teal", "teal"), new("deep-purple", "deep-purple darken-1"),
new("yellow", "yellow darken-4"), }; }
次に、Body ページを実装します。Body ページがメインコンテンツです。ここでは、Masa Blazor 公式サイトから Timelines コンポーネントを探して直接使用できます。公式サイトにはモバイル向けの Timeline のサンプルデモがあり、色を変更する機能はありませんが、問題ないのでコピーして修正します。

コードをコピーし、上部のツールバーを削除します。上部ツールバーはレイアウトページですでに記述されており、すべての子ページに適用されるため、ここでは再度記述する必要はありません。ただし、_color パラメータを Timeline ページに渡す方法を考慮する必要があります。ここではカスケードパラメータを使用し、CascadingValue で子ページにパラメータを渡し、子ページでは CascadingParameter で受け取ります。これにより、子ページで色変数を取得できます。

Timeline.razor の完全なコード:
@page "/"
<MCard Elevation="0" Class="mx-auto">
<MCard Dark Flat>
<MButton Absolute Bottom Color="@Color" Right Fab>
<MIcon>mdi-plus</MIcon>
</MButton>
<MImage
Src="https://cdn.masastack.com/stack/images/website/masa-blazor/cards/forest.jpg"
Gradient="to top, rgba(0,0,0,.44), rgba(0,0,0,.44)"
Dark
>
<MContainer Class="fill-height">
<MRow Align="@AlignTypes.Center">
<strong class="text-h1 font-weight-regular mr-6">8</strong>
<MRow Justify="@JustifyTypes.End">
<div class="text-h5 font-weight-light">Monday</div>
<div class="text-uppercase font-weight-light">February 2015</div>
</MRow>
</MRow>
</MContainer>
</MImage>
</MCard>
<MCardText Class="py-0">
<MTimeline AlignTop Dense>
<MTimelineItem Color="pink" Small>
<MRow Class="pt-1">
<MCol Cols="3">
<strong>5pm</strong>
</MCol>
<MCol>
<strong>New Icon</strong>
<div class="text-caption">Mobile App</div>
</MCol>
</MRow>
</MTimelineItem>
<MTimelineItem Color="@Color" Small>
<MRow Class="pt-1">
<MCol Cols="3">
<strong>3-4pm</strong>
</MCol>
<MCol>
<strong>Design Stand Up</strong>
<div class="text-caption mb-2">Hangouts</div>
<MAvatar>
<MImage
Src="https://avataaars.io/?avatarStyle=Circle&topType=LongHairFrida&accessoriesType=Kurt&hairColor=Red&facialHairType=BeardLight&facialHairColor=BrownDark&clotheType=GraphicShirt&clotheColor=Gray01&graphicType=Skull&eyeType=Wink&eyebrowType=RaisedExcitedNatural&mouthType=Disbelief&skinColor=Brown"
></MImage>
</MAvatar>
<MAvatar>
<MImage
Src="https://avataaars.io/?avatarStyle=Circle&topType=ShortHairFrizzle&accessoriesType=Prescription02&hairColor=Black&facialHairType=MoustacheMagnum&facialHairColor=BrownDark&clotheType=BlazerSweater&clotheColor=Black&eyeType=Default&eyebrowType=FlatNatural&mouthType=Default&skinColor=Tanned"
></MImage>
</MAvatar>
<MAvatar>
<MImage
Src="https://avataaars.io/?avatarStyle=Circle&topType=LongHairMiaWallace&accessoriesType=Sunglasses&hairColor=BlondeGolden&facialHairType=Blank&clotheType=BlazerSweater&eyeType=Surprised&eyebrowType=RaisedExcited&mouthType=Smile&skinColor=Pale"
></MImage>
</MAvatar>
</MCol>
</MRow>
</MTimelineItem>
<MTimelineItem Color="pink" Small>
<MRow Class="pt-1">
<MCol Cols="3">
<strong>12pm</strong>
</MCol>
<MCol>
<strong>Lunch break</strong>
</MCol>
</MRow>
</MTimelineItem>
<MTimelineItem Color="@Color" Small>
<MRow Class="pt-1">
<MCol Cols="3">
<strong>9-11am</strong>
</MCol>
<MCol>
<strong>Finish Home Screen</strong>
<div class="text-caption">Web App</div>
</MCol>
</MRow>
</MTimelineItem>
</MTimeline>
</MCardText>
</MCard>
@code{ [CascadingParameter] public string Color { get; set; } }
そして、このページでテーマカラーに応じて変更したい色を、Color 変数で制御するように変更します。

これで、タイムラインページが完成し、テーマカラーを切り替えられるようになりました。さらに、このサンプルを基に、例えば+ボタンをクリックしてモーダルを開き、時間タスクを追加してページにレンダリングするなどの機能を追加することも簡単にできますが、デモは行いません。この記事では主に、MAUI で Masa Blazor を使用する方法を紹介し、小さなデモを作成しました。参考にしていただき、MAUI + Blazor を使ってアプリケーションを作成してみてください。
完全なサンプルコード:codding-y/Maui.MasaBlazor (github.com)
オープンソースアドレス
MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks
MASA.Contrib:https://github.com/masastack/MASA.Contrib
MASA.Utils:https://github.com/masastack/MASA.Utils
MASA.EShop:https://github.com/masalabs/MASA.EShop
MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor
MASA Framework に興味があれば、コードの貢献、使用、Issue の提出など、お気軽にお問い合わせください。
