はじめに
.NET初心者をターゲットに、「なんとなくMAUI分かったかも」と思ってもらうための記事です。
私は主にMacで作業することが多いですが、Windowsでも同様に作業が進められると思います。
動作環境
- Apple M2 Mac mini (Sonoma 14.4.1)
 - .NET 8.0
 
まずは動かしてみる
プロジェクトの作成
Visual Studio で .NET MAUI アプリ を選び、プロジェクト名: MauiExample でプロジェクトを新規作成します。
VSCodeの場合は
dotnet new maui -o MauiExampleで同じことができます。
実行
Visual Studioでプロジェクトを開き、デバッグ ターゲットがWindowsの状態で実行します。
Mac+VSCodeの場合は
dotnet build -t:Run -f net8.0-maccatalystで実行できます。
以下の画面が起動したらOKです。
ボタンをクリックしたら何が起こるのかを確認してください。
うまく動かなかったら初めてのアプリを構築するを参考にしてください。
プロジェクトの構造について
作成されたプロジェクトのMauiExampleフォルダを開くと以下のようになっています。
MauiProgram.cs
プログラムを起動した時、最初に実行されるファイルです。
using Microsoft.Extensions.Logging;
namespace MauiExample;
public static class MauiProgram
{
	public static MauiApp CreateMauiApp()
	{
		var builder = MauiApp.CreateBuilder();
		builder
			.UseMauiApp<App>()
			.ConfigureFonts(fonts =>
			{
				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
				fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
			});
#if DEBUG
		builder.Logging.AddDebug();
#endif
		return builder.Build();
	}
}
builderインスタンスを作り、このインスタンスに対して色々設定をしています。
この
◯◯builderに設定をしていくパターンは、ASP.NET Coreなどの別フレームワークでも同様です。覚えておいて損はありません。
var builder = MauiApp.CreateBuilder();
「App(App.xaml + App.xaml.cs)を使いますよ」って宣言(.UseMauiApp<App>()部分)と
使用するフォントの設定(.ConfigureFonts(...))をしています。
App.xaml, App.xaml.cs
App.xamlにはアプリ全体から参照できるリソース(参考:リソース ディクショナリ
)を指定します。リソースの本体は「Resources」フォルダーに保存されています。
ここではColors.xaml(使用する色に関する定義), Style.xaml(使用するボタンなどのコントロールに関する定義)が指定されています。
例えば、「ボタンを全部赤色にしたい」といった場合、全ボタンに一つずつbackgroundColor="Red"を書いていくのは面倒なので、赤色をボタンに設定するスタイルをResources」フォルダー内に作ってしてそれを各ページに適用するって感じで使います。
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiExample"
             x:Class="MauiExample.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/Styles/Colors.xaml" />
                <ResourceDictionary Source="Resources/Styles/Styles.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
App.xaml.csではルートページとしてAppShell(AppShell.xaml + AppShell.xaml.cs)を指定しています。
MainPageはAppの継承元であるApplicationクラスで定義されているプロパティですので、例えばRootPageなどに変更するとエラーになります。一応。
namespace MauiExample;
public partial class App : Application
{
	public App()
	{
		InitializeComponent();
		MainPage = new AppShell();
	}
}
AppShell.xaml, AppShell.xaml.cs
AppShellはナビゲーション機能などを提供するためのShellを継承したクラスです。
簡単にいうと画面の切り替えを行うためのものですが、今はMainPageしかないのであまり意味ないですね。
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MauiExample.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiExample"
    Shell.FlyoutBehavior="Disabled"
    Title="MauiExample">
    <ShellContent
        Title="Home"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />
</Shell>
ナビゲーション方式はFlyout、またはTabがあります。リンク先のサンプルコードを見ればイメージが掴みやすいと思います。
AppShell.xaml.csの方は初期化だけで、特に何もしていません。
namespace MauiExample;
public partial class AppShell : Shell
{
	public AppShell()
	{
		InitializeComponent();
	}
}
MainPage.xaml, MainPage.xaml.cs
プログラム実行時に表示された画面のメイン部分です。
- ScrollView: スクロールを有効にする
 - VerticalStackLayout: コントロールを垂直方向に並べる
 - Image: 画像を表示する
 - Label: テキストを表示する
 - Button: ボタンを表示する
 
を使用して実装されています。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiExample.MainPage">
    <ScrollView>
        <VerticalStackLayout
            Spacing="25"  // コンポーネントとコンポーネントに 25px 隙間を設ける
            Padding="30,0" // パディングを左右に30px, 上下に 0pxに設定
            VerticalOptions="Center"> // 垂直方向に中央揃え
            <Image
                Source="dotnet_bot.png" // Resources¥Imagesにある画像ファイルを指定
                SemanticProperties.Description="Cute dot net bot waving hi to you!"
                HeightRequest="200" // 画像の高さを指定
                HorizontalOptions="Center" /> // 水平方向に中央揃え
            <Label
                Text="Hello, World!" // 表示するテキスト
                SemanticProperties.HeadingLevel="Level1"
                FontSize="32" // テキストのフォントサイズ
                HorizontalOptions="Center" />  // 水平方向に中央揃え
            <Label
                Text="Welcome to .NET Multi-platform App UI"
                SemanticProperties.HeadingLevel="Level2"
                SemanticProperties.Description="Welcome to dot net Multi platform App U I"
                FontSize="18"
                HorizontalOptions="Center" /> 
            <Button
                x:Name="CounterBtn" // ButtonオブジェクトをMainPage.xaml.cs内で参照するための指定
                Text="Click me" // ボタンの中に表示するテキスト
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked" // クリックした時の処理
                HorizontalOptions="Center" /> // 水平方向に中央揃え
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>
Imageに
Source="dotnet_bot.png"を指定していますが、不思議なことにResouces/Imagesフォルダにはdotnet_bot.svgファイルしかありません。
MAUIにはビルド時にsvgをpngに変換する仕組みがあるのでdotnet_bot.pngをちゃんと参照できるのです。
参考: ローカル画像を読み込む
SemanticPropertiesで始まるプロパティについてはセマンティック プロパティを使用してアクセス可能なアプリを構築するを参照してください。
注目すべきはButtonに指定された以下の2つです。
- x:Name="CounterBtn"
 - Clicked="OnCounterClicked"
 
これを踏まえて、MainPage.xaml.csを見てみましょう
namespace MauiExample;
public partial class MainPage : ContentPage
{
	int count = 0;
	public MainPage()
	{
		InitializeComponent();
	}
	private void OnCounterClicked(object sender, EventArgs e)
	{
		count++;
		if (count == 1)
			CounterBtn.Text = $"Clicked {count} time";
		else
			CounterBtn.Text = $"Clicked {count} times";
		SemanticScreenReader.Announce(CounterBtn.Text);
	}
}
MainPage.xaml.csにはプロパティ: CounterBtnが定義されていないのに、まるで定義済みかのようにCounterBtn.Textでボタンのテキストを参照・変更しています。
また、OnCounterClickedはMainPage.xaml上でButtonのClickedに指定されていました。
これがXamlとC#を組み合わせて画面+処理を実装する基本的な形になります。
XamlとC#(コードビハインド)の連携
これまで説明してきたAPP, AppShell, MainPageには.xamlと.xaml.csが対になって存在していました。これらの対のファイルは連携して動作します。
対応付けは
- 
.xaml.csで定義されている名前空間+クラス名 - 
.xamlのx:Classで指定された名前空間+クラス名 
で行われます。
ファイル名やファイルパスは関係ないので、両ファイルを全く異なるパス、ファイル名で置いておくことはできますがオススメしません。同階層に
.xamlと.xaml.csのペアで置いておくのが基本です。
試しにMainPage.xamlの x:Class="MauiExample.MainPage"を変えてみましょう。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiExample.TopPage"> // TopPageに変更
この状態でMainPage.xaml.csを開くと警告が出るようになります。
CounterBtnが認識出来なくなっていますね。
逆にMainPage.xaml.cs側のクラス名を変更しても同じ状態になります。
補足:Xamlは必須ではない
「.xamlと.xaml.csのペアで動作するのが基本」と書きましたが、実は.xaml無しでも実装はできます。
例えば、画面上にLabelを表示させる場合、.xaml.cs内でインスタンスを作成すればXaml内で<Label ... />を記述したのと同等になります。
Label label = new Label { Text = "Hello world" };
// <Label Text="Hello world" /> と同等
とはいえ、UIに関するコードはXaml、動作に関わるコードは.xaml.csに実装する方がコードの見通しがいいのでそちらをオススメします。
その他のフォルダについて
- 
bin: ビルドの出力結果である実行可能なファイルの保存先
 - 
obj: ビルドの一時ファイル置き場
 - 
Platforms: プログラム起動時に、OSごとに異なる処理を実行させたい場合に使います(参考: マルチターゲットの構成)
 - 
Properties: アプリケーションの起動とデバッグの設定を構成するために使用される
launchSettings.json置き場。launchSettings.jsonでは、プロファイル、環境変数、引数などを構成する。 - 
Resouces: リソース ディクショナリ置き場。
 
今後の予定
- MVVM Toolkitを使用してMVVMにする
 - CollectionViewでコレクションを表示する
 - ContentPageを複数のContentViewに分割する
 - Layoutのコツなど
 



