SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Windowsで進化するマルチプラットフォームGUI開発

.NET MAUIでラーメンタイマーアプリを作ろう【フレームワークの使い方を解説】

Windowsで進化するマルチプラットフォームGUI開発 第3回

  • X ポスト
  • このエントリーをはてなブックマークに追加

ラーメンタイマーアプリ

 今度は、テンプレートのページの変更ではなく、新しいページを追加してラーメンタイマーアプリを作ります。今回のアプリでは、初期状態では、3分経過するとメッセージを表示します。また、設定する時間は、変更できるようにしました。

ラーメンタイマー

ラーメンタイマー

 開始ボタンをクリックすると、表示されている残り時間が減っていきます。そして残り時間が0になると、メッセージが表示されます。

メッセージ表示

メッセージ表示

新しいページの追加

 最初に、あらためて新規プロジェクトを作成しましょう。ここでは、RamenTimerという名前のプロジェクトにしました。前回解説したように、テンプレートのアプリでは、Shellコントロールの中にMainPageビューを定義しています。ただ1画面だけの単純なアプリでは、もっとシンプルな構成も可能です。

 新しい空のページを追加して、そのページを直接表示する構成に変更してみます。Visual Studioのメインメニューから、[プロジェクト]ー[新しい項目の追加]を選択します。次のようなダイアログが表示されるので、左欄から、.NET MAUIを選択します。そして、表示された一覧から、ContentPage(XAML)を選びます。ここでは名前を、TimerPage.xamlとしました。

新しい項目の追加
新しい項目の追加

 追加ボタンをクリックすると、プロジェクトにTimerPage.xamlとTimerPage.xaml.csが追加され、TimerPage.xamlの内容が表示されます。(もしx:Class属性が、プロジェクト名.TimerPageになっていない場合は、次のように修正し、TimerPage.xaml.csの1行目にあるnamespace定義も、namespace RamenTimer;に修正してください)

[リスト5]TimerPage.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="RamenTimer.TimerPage"
             Title="TimerPage">
    <StackLayout>
        <Label Text="Welcome to .NET MAUI!"
                VerticalOptions="Center" 
                HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

 次に、追加したページを表示するように変更します。App.xaml.csのAppクラスのコンストラクターで、MainPageプロパティの設定をTimerPageに変更します。

[リスト6]App.xaml.cs
public App()
{
	InitializeComponent();

	// MainPage = new AppShell();
	MainPage = new TimerPage();
}

 ここで一旦、アプリをビルドして確認してみましょう。次のような画面が表示されるはずです。

空ページ表示

空ページ表示

コントールの配置

 それでは、タイマーアプリのパーツをページに配置していきましょう。追加したページには、すでに<StackLayout>が定義されていますので、このレイアウトを利用します。StackLayoutのLabelコントロールを変更し、さらにProgressBarコントロールを追加します。

[リスト7]TimerPage.xaml
<StackLayout
    Spacing="10"
    VerticalOptions="Center">

    <Label Text="00:00"
        FontSize="36"
        FontAttributes="Bold"
        HorizontalTextAlignment="Center"
        x:Name="MinutesLabel"/>

    <ProgressBar
        x:Name="PrgBar"
        Progress="0"
        ProgressColor="Orange" />

</StackLayout>

 StackLayoutのVerticalOptionsプロパティは、垂直方向の位置を設定します。Labelコントロールの、HorizontalTextAlignmentは、水平方向の位置になります。いずれも中央に設定しています。Spacingプロパティは、子コントロール間のスペースです。

 プロパティについては、Visual StudioのIntelliSense機能によって、候補が表示されるので、そこから選択することで入力できます。細かいスペルまでは覚える必要はありません。また、ホットリロード機能のおかげで、アプリを起動したままXAMLを編集して、表示具合を確認することができます。

ボタンの配置

 次は、タイマー開始(停止)のボタンと、設定値を変更するためのボタンを追加してみましょう。今回は、3つのボタンを横にならべるレイアウトにしました。次のように、StackLayoutの中に、ボタン用のStackLayoutを定義します。

[リスト8]TimerPage.xaml
<StackLayout 
~略~
    <StackLayout
        Orientation="Horizontal"
        HorizontalOptions="Center"
        Spacing="10" >

        <Button
            WidthRequest="100"
            x:Name="M1Button"
            Clicked="OnMinusButton"
            Text="-1分" />

        <Button
            WidthRequest="100"
            x:Name="StartButton"
            Clicked="OnStartButton"
            Text="開始" />

         <Button
            WidthRequest="100"
            x:Name="P1Button"
            Clicked="OnPlusButton"
            Text="+1分" />
    </StackLayout>
~略~

 真ん中のボタンがタイマーを開始するボタンになります。その左右に、設定時間を1分単位で増減するボタンを配置しています。なお、ボタンのWidthRequestプロパティは、ボタンの横幅を設定するプロパティです。

ソースコードの追加

 画面の編集が完了したら、次はタイマーの処理を追加しましょう。アプリを起動していたら、いったんここで終了します。まずは、TimerPageクラスにフィールドを追加します。

[リスト9]TimerPage.xaml.cs
~略~

public partial class TimerPage : ContentPage
{
    // 設定時分(初期値は3分)
    private TimeOnly StartTime = new(0, 3);

    // 残り時分(初期値は3分)
    private TimeOnly LeftTime = new(0, 3);

    // 実行中ならtrue
    private bool IsLive = false;

~略~

 StartTimeは、タイマーの設定値、LeftTimeは、タイマー開始後の残り時間としています。System.TimeOnly構造体は、時刻のみを保持する構造体です。ここでは、TimeOnly構造体のコンストラクター(時間と分の指定)を利用して初期化しています。次に、タイマーの残り時間を示すラベルと、プログレスバーの更新処理を追加しましょう。

[リスト10]TimerPage.xaml.cs
~略~

    // ラベル、プログレスバーの表示更新
    private void SetLabel()
    {
        MinutesLabel.Text = LeftTime.ToString("mm分ss秒ff");
        PrgBar.Progress = (StartTime - LeftTime).TotalSeconds / (StartTime - new TimeOnly(0, 0)).TotalSeconds;
    }

    public TimerPage()
    {
        InitializeComponent();
        SetLabel();
    }
~略~

 SetLabelメソッドでは、変数LeftTimeを、0.01秒単位まで表示できるようにしています。また、プログレスバーのProgressプロパティには、変数LeftTimeが設定値と同じなら0、残り時間が0になったら、1となるように設定しています。

タイマー(時刻の減算)処理

 次は、タイマー(時刻の減算)処理を追加しましょう。

[リスト11]TimerPage.xaml.cs
~略~

    private void Toggle()
    {
        IsLive = !IsLive;  // 実行中フラグを反転

        // ボタン名を変更する
        StartButton.Text = (IsLive) ? "停止" : "開始";
    }

    // 残り時分を減算する
    private async void DecreaseTime()
    {
        var span = 10; // 10ミリ秒

        while (IsLive)
        {
            await Task.Delay(TimeSpan.FromMilliseconds(span));
            LeftTime = LeftTime.Add(TimeSpan.FromMilliseconds(-span));

            SetLabel();

            if ((LeftTime.Minute | LeftTime.Second | LeftTime.Millisecond) == 0)
            {
                Toggle();
                await DisplayAlert("終了", "ラーメンができました", "OK");
            }
        }
    }

~略~

 Toggleメソッドは、実行中フラグを反転して、ボタン表示をフラグに合わせて変更する処理です。ボタンは、最初は「開始」と表示されますが、タイマー開始後は、「停止」となります。つまり、タイマー開始後は、開始ボタンから停止ボタンに変更する、ということです。

 DecreaseTimeメソッドが、タイマーのメイン処理となります。whileループでは、実行中フラグがtrueの間、Task.Delayで一定期間処理を停止させ、その後に、LeftTimeから同じ停止した時刻分の値を減算しています。LeftTimeが0になれば、DisplayAlertメソッドで、画面にメッセージを表示します。

 なお、Task.Delayは、非同期処理となりますので、先頭にawaitをつけ、Task.Delayを呼び出しているメソッドDecreaseTimeには、asyncを付加する必要があります。

ボタンイベント

 最後に、ボタンがクリックされた時に実行されるメソッドを追加します。メソッド名は、TimerPage.xamlで定義した名前にします。

[リスト12]TimerPage.xaml.cs
// 開始(停止)ボタンのクリック
    private void OnStartButton(object sender, EventArgs e)
    {
        Toggle();
        DecreaseTime();
    }

    // +1分ボタンのクリック
    private void OnPlusButton(object sender, EventArgs e)
    {
        LeftTime = LeftTime.Add(TimeSpan.FromMinutes(1));
        StartTime = LeftTime; // 開始時分の設定
        SetLabel();
    }

    // -1分ボタンのクリック
    private void OnMinusButton(object sender, EventArgs e)
    {
        LeftTime = LeftTime.Add(TimeSpan.FromMinutes(-1));
        StartTime = LeftTime; // 開始時分の設定
        SetLabel();
    }
~略~

 OnStartButtonメソッドでは、実行中フラグを反転して、DecreaseTimeメソッドを呼び出します。OnPlusButton、OnMinusButtonメソッドでは、時間を増減して、変数StartTimeに設定しています。なお、LeftTime、StartTimeとも、構造体なので、=演算子では、値のコピーとなります。

最後に

 今回は、.NET MAUIでラーメンタイマーアプリを作成しました。.NET MAUでは、豊富なUIコントロールを利用すれば、簡単に画面を作成することができます。もちろん、画像を駆使するようなゲームアプリは難しいのですが、GUIフォームが主体となるアプリでは、手軽にマルチプラットフォームに対応したアプリが作成できます。次回は、.NET MAUI Blazorの解説を予定しています。

参考文献

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Windowsで進化するマルチプラットフォームGUI開発連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 高江 賢(タカエ ケン)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16002 2022/06/15 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング