2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

.NET6 MAUI preview4でMAUIアプリの作り方を見てみる

Posted at

.NET6 preview4

2021/05/25に.NET6 preview4が出ましたね!
それと同時にMAUI preview4が出ました。

さっそくサンプルのWeatherTwentyOneを見つつ、全体の作りと、preview3であれ?と思ったところを見てみます。

プラットフォーム毎の起動パターン

基本的にはXamarinの起動パターンを踏襲しています。

iOS / MacCatalyst

MainからUIApplication.Mainを使ってUIKitのアプリケーションを起動します。
そして[Register("")]されている名前のDelegateを呼び出します。
…この辺、まんまXamarinですね。

[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate<Startup>
{
}

呼び出されるDelegateはMauiUIApplicationDelegate<>を継承したクラスで、設定されているテンプレートのクラスをスタートアップにして呼び出しているようです。

Android

[Activity(MainLauncher = true)]でデフォルトActivityを指定。
[Application]でアプリケーションクラスを指定します。
やっぱりXamarinです。

[Activity(MainLauncher = true)]
public class MainActivity : MauiAppCompatActivity
{
}

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

[Application]のクラスはMauiApplication<>を継承したクラスで、設定されているテンプレートのクラスをスタートアップにして呼び出しているようです。

WinUI

WinUIの場合、少しジレンマがあるようです。

起動に使用するApp.xamlApp.xaml.csは共通部分に使いたいです。
しかも、XAMLでプリケーションを指定したいのだがスタートアップクラスをテンプレートとして指定したい。
ということで、MiddleAppみたいなのをいったん作った後、XAMLで指定するようです。
(サンプルでも「イケてないね」みたいなコメント書いてあります…)

<local:MiddleApp
    x:Class="WeatherTwentyOne.WinUI.WindowsApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WeatherTwentyOne.WinUI">
</local:MiddleApp>
public partial class WindowsApp : MiddleApp
{
}

public class MiddleApp : MauiWinUIApplication<Startup>
{
}

アプリケーションのクラスはMauiWinUIApplication<>を継承したクラスで、設定されているテンプレートのクラスをスタートアップにして呼び出しているようです。

Startup

各プラットフォームで指定したStartupクラスは、起動時の共通設定を行うようになっています。
ASP.NetCoreのような感じですね。

public class Startup : IStartup
{
	public void Configure(IAppHostBuilder appBuilder)
	{
		appBuilder
			.UseCompatibility()
			.UseMauiApp<App>()
			.ConfigureServices(services =>
			{
# if WINDOWS
				services.AddSingleton<ITrayService, WinUI.Windows.TrayService>();
				services.AddSingleton<INotificationService, WinUI.Windows.NotificationService>();
# elif MACCATALYST
				services.AddSingleton<ITrayService, MacCatalyst.TrayService>();
				services.AddSingleton<INotificationService, MacCatalyst.NotificationService>();
# endif
			})
			.ConfigureFonts((fonts)=>
			{
				fonts.AddFont("fa-solid-900.ttf", "FontAwesome");
				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
				fonts.AddFont("OpenSans-SemiBold.ttf", "OpenSansSemiBold");
			});
	}
}

サービス登録などもここで行います。
(UnityやDrylocのようなDIものではなく、Xamarinのプラットフォーム毎のサービス)

この後、この中のUseMauiApp<>で指定したMAUI本来のアプリケーションを起動させるようです。

App.xaml, App.xaml.cs

MAUIのアプリケーション起動内では、ウインドウを作ります。

public partial class App : Microsoft.Maui.Controls.Application
{
	protected override IWindow CreateWindow(IActivationState activationState)
	{
		Microsoft.Maui.Controls.Compatibility.Forms.Init(activationState);

		return new Microsoft.Maui.Controls.Window(
			new NavigationPage(
				new HomePage()
			)
		);
	}
}
//(Windowを作るところだけを抜粋)

Windowは、Windowクラスを使って作ればよいです。
そして、コンストラクタ引数でPageクラスを指定します。

preview3では…(余談)

preview3のIWindowでは、IViewを保持して、継承したビューを表示するようになっていました。
なので、

public class MainPage : ContentPage
{
	public IView View => Content;
}

public class Window : IWindow
{
	public IPage Page { get; }
	public IView View => Page.View;
}

のような実装になっていたので、「あれ?Pageはどこいった?あれNSViewControllerに変換できただろう?」と思ったものです。
(基本macOSでやってたもので…)

というのも、MauiUIApplicationDelegateの実装で、

			Window = new UIWindow
			{
				RootViewController = window.View.ToUIViewController(mauiContext)
			};

という、ViewをUIViewControllerに変換している部分があったため…。
preview4のWindowの実装(Window.Impl.cs)で、下記のような指定になっているので、ああ、ちゃんとPageが指定できるようになっているんだな、とは思いましたが。

		public Page? Page
		{
			get => _page;
			set
			{
				if (_page != null)
					InternalChildren.Remove(_page);

				_page = value;

				if (_page != null)
					InternalChildren.Add(_page);

				if (value is NavigableElement ne)
					ne.NavigationProxy.Inner = NavigationProxy;
			}
		}

		IView IWindow.View
		{
			get => Page ?? throw new InvalidOperationException("No page was set on the window.");
			set => Page = (Page)value;
		}

最後に

というわけで、無事画面周りの実装も

Window
  Page
    View

と、階層構造になっていることが確認でき、一安心したpreview4でした。

じっさいの作成では、MAUIのテンプレートから作って必要なプラットフォームのみ作成、ページの作成にはXamarinで使っていたPageやViewを使えばいい、ということになりそうです。
ということで、テンプレートとして出力されるソースをいじるのは、App.xaml.csあたりからで良さげ。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?