13
4

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 1 year has passed since last update.

N/S高等学校Advent Calendar 2022

Day 2

.NET MAUIがVisual Studio for Mac 17.4で利用可能になったので触ってみた

Last updated at Posted at 2022-12-01

この記事は N/S高等学校 Advent Calendar 2022 の2日目の記事になります。

概要

タイトル通りにはなりますが、MacでVisual Studioを触ったことがないので.NET MAUIがリリースされた&Macでも利用可能になったということで触れてみました。ついでに最近のMVVMパターンの書き方も進化しているようなのでこちらも少し触れてみました。

.NET MAUIとは

C#とXAMLを使ってWindows、Mac、Android、iOSのアプリケーションを作成するためのクロスプラットフォームフレームワークです。
今まではXamarinでしたがこれがMAUIに置き換わったのですね。

環境

執筆時時点でMacOS上でMAUIアプリの作成には以下の環境が必要でした。

  • Visual Studio 2022 for Mac 17.4
  • macOS Monterey 12.5
  • Xcode 14.1

触るモノ

プロジェクトを作成すると出来上がる、ボタンをクリックした数をカウントするアプリです。
スクリーンショット 2022-11-28 15.15.07.png

プロジェクト作成時のコード

コードビハインドで記述されています。
OnCounterClicked()でボタンのテキストを直接変更しているだけですね。

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="DefaultApp.MainPage">

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">

            ~~~~~~中略~~~~~~

            <Button
                x:Name="CounterBtn"
                Text="Click me"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
MainPage.xaml.cs
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);
	}
}

MVVMを自力で書く場合

せっかくなのでMVVMにしてみます。
INotifyPropertyChangedを実装したクラスを用意し、それを継承したMainPageViewModel(ViewModelクラス)を作成します。
ViewModelにはバインディングするためのプロパティとコマンドを書いていきます。

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"
             xmlns:local="clr-namespace:OldBinding.ViewModel"
             x:Class="OldBinding.MainPage">

    <ContentPage.BindingContext>
        <local:MainPageViewModel />
    </ContentPage.BindingContext>

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">

            ~~~~~~中略~~~~~~

            <Button
                x:Name="CounterBtn"
                Text="{Binding Text}"
                SemanticProperties.Hint="Counts the number of times you click"
                Command="{Binding Command}"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
ViewModelBase.cs
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        private string NameProperty;

        public string Name
        {
            get
            {
                return NameProperty;
            }
            set
            {
                if (NameProperty != value)
                {
                    NameProperty = value;
                    NotifyPropertyChange("Name");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChange(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
MainPageViewModel.cs
	public class MainPageViewModel : ViewModelBase
	{
        private string text = "click me";
        private int count = 0;

        public MainPageViewModel()
        {
            Command = new Command(Count);
        }

        public string Text
        {
            get
            {
                return text;
            }
            set
            {
                if (text != value)
                {
                    text = value;
                    NotifyPropertyChange("Text");
                }
            }
        }

        public ICommand Command
        {
            get;
            protected set;
        }

        private void Count()
        {
            count++;

            if (count == 1)
                Text = $"Clicked {count} time";
            else
                Text = $"Clicked {count} times";
        }
    }

うーん、とても面倒くさいですね。。

CommunityToolkit.Mvvmを使ってみる

Microsoft謹製のMVVM開発をサポートしてくれる便利なライブラリーがあります。
Nugetパッケージの管理からライブラリーをインストールします。
スクリーンショット 2022-11-28 17.19.30.png

それではこのライブラリーを使ってコードを書いてみます。

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"
             xmlns:local="clr-namespace:NewBinding.ViewModel"
             x:Class="NewBinding.MainPage">

    <ContentPage.BindingContext>
        <local:MainPageViewModel />
    </ContentPage.BindingContext>

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">

            ~~~~~~中略~~~~~~

            <Button
                x:Name="CounterBtn"
                Text="{Binding Text}"
                SemanticProperties.Hint="Counts the number of times you click"
                Command="{Binding CommandCommand}"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

MainPageViewModel.cs
	[INotifyPropertyChanged]
	public partial class MainPageViewModel
	{
        private int count = 0;

        public MainPageViewModel()
		{
		}

		[ObservableProperty]
        private string text = "click me";

        [RelayCommand]
		private void Command()
		{
            count++;

            if (count == 1)
                Text = $"Clicked {count} time";
            else
                Text = $"Clicked {count} times";

        }
    }

なんということでしょう。コード量がこれだけになってしまいました。
INotifyPropertyChangedはクラスに属性をつけるだけで実装は不要となりました。
プロパティも変数にObservableProperty属性をつけると自動的に生成してくれるようです。
この場合textからTextプロパティを生成してくれます。
コマンドに関してもメソッドにRelayCommand属性をつけるとメソッド名+Commandというコマンドが自動生成されるようです。
サンプルのメソッド名がCommandなのでCommandCommandというおかしな名前になってしまいましたが、、
あと、クラスをpartialにしないとエラーになってしまうことが注意点でした。(なぜわざわざpartialにしないとダメなのでしょう。)

最後に

さて、今回初めてMac上でMAUIアプリを作成してみました。
前提条件としてXCodeのインストールが必要なのが手間ですがそこは仕方ありませんね。
Xamlには慣れる必要がありますが、C#でクロスプラットフォームアプリが作成できるのは魅力的ですね。
CommunityToolkit.Mvvmは裏でコードが自動生成されるので初見ではなんで動いてるんだ?と思わせかねないコードになってしまう感じがしますがルールさえ押さえておけばスッキリと書けるので良いのではないでしょうか。

13
4
1

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
13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?