.NET MAUI RC3を試してみる（中編）


# .NET MAUIのテンプレートソースをチェック

「[前編](https://qiita.com/hqf00342/items/d4a7a262cbec7b480cc8)」でWindowsアプリはコンパイルできましたので、このサンプルソースをチェックします。今回も1行もソースを書いてません。

https://qiita.com/hqf00342/items/d4a7a262cbec7b480cc8

プロジェクト作成直後のテンプレートソースはこちら

https://github.com/hqf00342/MauiApp1/tree/757e342f4803626a7dc56cb10e6415bcd9cdc3d5/MauiApp1

## ファイル一覧

スケルトンにしてはファイル数があるように見えますが
- Main()相当の[エントリーポイント](#エントリーポイント)
- [GUI部分](#GUI部)

の2つに分かれています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54535/d7c06c45-f1a7-cf86-087d-e22d41af9660.png" width="50%">

/platformsフォルダ下部のソースは基本いじらずに、設定は一番下の `MauiProgram.cs`、GUI周りはxamlとコードビハインドを変更する形になります。

## エントリーポイント

### Windowsの場合
Windows固有のエントリーポイントは `/Platforms/Windows/App.xaml(.cs)` のようです。中間生成コードでもこのクラスに `Main()` が生成されています。

```csharp:/Platforms/Windows/App.xaml.cs
using Microsoft.UI.Xaml;
namespace MauiApp1.WinUI;

public partial class App : MauiWinUIApplication
{
    public App()
    {
        this.InitializeComponent();
    }
    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
```

注目は `MauiProgram.CreateMauiApp()` を呼び出すようにoverrideしている点です。これはAndroid,
iOSも同様で、実質的なエントリーポイントは `MauiProgram.cs` になるようです。

### Androidの場合

Androidも `MauiProgram.CreateMauiApp()`が呼び出されています。
```csharp:/Platforms/Android/MainApplication.cs
using Android.App;
using Android.Runtime;

namespace MauiApp1;

[Application]
public class MainApplication : MauiApplication
{
	public MainApplication(IntPtr handle, JniHandleOwnership ownership)
		: base(handle, ownership)
	{
	}

	protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
```

### Mac / iOS

MacCatalystとiOSは同じコードになっています。Windows,Androidと同じように `MauiProgram.CreateMauiApp()` を呼び出しているだけです。

```csharp:Program.cs
using ObjCRuntime;
using UIKit;

namespace MauiApp1;

public class Program
{
	// This is the main entry point of the application.
	static void Main(string[] args)
	{
		// if you want to use a different Application Delegate class from "AppDelegate"
		// you can specify it here.
		UIApplication.Main(args, null, typeof(AppDelegate));
	}
}
```

```csharp:AppDelegate.cs
using Foundation;

namespace MauiApp1;

[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
	protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
```

### 共通のエントリーポイント

ということで、WindowsもAndroidもiOSも必ず `MauiProgram.CreateMauiApp()` メソッドを呼び出しています。つまりここがプラットフォームに依存しない共通のエントリーポイントとなります。

```csharp:MauiProgram.cs
namespace MauiApp1;

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");
			});

		return builder.Build();
	}
}

```

ASP.NETやBlazerと同様のGeneric Hostパターン、公式には builder patternと言うようです。
サンプルではフォントをエイリアス名を付けて登録しています。
そして`UseMauiApp<App>()`を使って `App`クラスが呼び出され、GUIが定義されていきます。
手の込んだアプリを作る場合はここにハンドラーを登録していくことになると思います。

詳しくは以下を参照してください。
https://docs.microsoft.com/ja-jp/dotnet/maui/fundamentals/app-startup

## GUI部

GUI部分としてはAppクラスを頂点とした xaml/xaml.csファイル群になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54535/48a462a9-9b8b-9ffc-1060-49ad0afbd6d6.png)

### App クラス

WPFなどと同様に `ResouceDictionary` でリソース定義されています。
Appクラスは `Application` クラスを継承しており、`MainPage`プロパティに実際のページを生成するようです。

```xml:App.xaml
<?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:MauiApp1"
             x:Class="MauiApp1.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/Colors.xaml" />
                <ResourceDictionary Source="Resources/Styles.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
```

```csharp:App.xaml.cs
namespace MauiApp1;

public partial class App : Application
{
	public App()
	{
		InitializeComponent();

		MainPage = new AppShell();
	}
}
```

サンプルアプリでは `MainPage = new AppShell()` ですので次は `AppShell`を確認します。


### AppShell クラス 
csファイルの方はいつもの `InitializeComponent()`の呼び出しだけなので割愛して、xamlだけ見てみます。

```xml:Appshell.xaml
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MauiApp1.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiApp1"
    Shell.FlyoutBehavior="Disabled">

    <ShellContent
        Title="Home"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />
</Shell>
```

Shell コントロールが作られています。詳しくは[公式ドキュメント](https://docs.microsoft.com/ja-jp/dotnet/maui/fundamentals/shell/)を見ていただくとして、一般的なアプリによくある機能を持っている複合コントロールのようです。以下の機能を持っています。

- メニュー機能（ドロップダウンする3本線のアレ）
- ページ遷移機能
- タブ
- 検索ボックス、検索機能

### MainPage

`AppShell`でページとして定義されているのがこの `MainPage` クラスです。
画面に表示されているのがこれになります。

```xml:MainPage.xaml
<?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="MauiApp1.MainPage">
			 
    <ScrollView>
        <VerticalStackLayout 
            Spacing="25" 
            Padding="30,0" 
            VerticalOptions="Center">

            <Image
                Source="dotnet_bot.png"
                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"
                Text="Click me"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>
 
</ContentPage>
```

このxamlの結果が以下のGUI画面になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54535/62447916-6a61-b789-62da-224e68110270.png" width="70%">

一番上の 「Home」 は`Shell`の機能です。
「Click me」の実装はコードビハインドにあります。

```csharp:MainPage.xaml.cs
namespace MauiApp1;

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);
	}
}
```
## 参考

.NET MAUIらしいところは 今のところShellぐらいしか出てきてませんが公式ドキュメントも確認してください。

公式ドキュメント

https://docs.microsoft.com/ja-jp/dotnet/maui/

エントリーポイント

https://docs.microsoft.com/ja-jp/dotnet/maui/fundamentals/app-startup

Shell

https://docs.microsoft.com/ja-jp/dotnet/maui/fundamentals/shell/