6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.Net MAUI に入門する (新規作成したプロジェクトについて)

Last updated at Posted at 2024-04-04

はじめに

.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の状態で実行します。

image.png

Mac+VSCodeの場合は dotnet build -t:Run -f net8.0-maccatalystで実行できます。

以下の画面が起動したらOKです。

ボタンをクリックしたら何が起こるのかを確認してください。

image.png

うまく動かなかったら初めてのアプリを構築するを参考にしてください。

プロジェクトの構造について

作成されたプロジェクトのMauiExampleフォルダを開くと以下のようになっています。

image.png

MauiProgram.cs

プログラムを起動した時、最初に実行されるファイルです。

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」フォルダー内に作ってしてそれを各ページに適用するって感じで使います。

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: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などに変更するとエラーになります。一応。

App.xaml.cs
namespace MauiExample;

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

		MainPage = new AppShell();
	}
}

AppShell.xaml, AppShell.xaml.cs

AppShellはナビゲーション機能などを提供するためのShellを継承したクラスです。

簡単にいうと画面の切り替えを行うためのものですが、今はMainPageしかないのであまり意味ないですね。

AppShell.xaml
<?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の方は初期化だけで、特に何もしていません。

AppShell.xaml.cs
namespace MauiExample;

public partial class AppShell : Shell
{
	public AppShell()
	{
		InitializeComponent();
	}
}

MainPage.xaml, MainPage.xaml.cs

プログラム実行時に表示された画面のメイン部分です。

を使用して実装されています。

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="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を見てみましょう

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でボタンのテキストを参照・変更しています。

また、OnCounterClickedMainPage.xaml上でButtonClickedに指定されていました。

これがXamlC#を組み合わせて画面+処理を実装する基本的な形になります。

XamlとC#(コードビハインド)の連携

これまで説明してきたAPP, AppShell, MainPageには.xaml.xaml.csが対になって存在していました。これらの対のファイルは連携して動作します。

対応付けは

  • .xaml.csで定義されている 名前空間+クラス名
  • .xamlx: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を開くと警告が出るようになります。

image.png

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のコツなど
6
5
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
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?