C#なんぞ

C#に関するあれこれ。現在は「Raspberry PiをC#でプログラミング!」しようとしています!

バックグラウンド!

じゃあ、GUIなしで!

Raspberry PiではIoT Remote Clientがどうやら使えないようなので、GUIのないバックグラウンドのプロジェクトを作ってみましょう! (Raspberry Piにディスプレイを直結すれば、もちろん映ります)

csharpwhat.hatenablog.com

Microsoftのサイトに手順が載っていますので、それにしたがって進めます!

docs.microsoft.com

テンプレートのインストール!

まず、Windows IoTでのバックグラウンド・アプリのテンプレートがあるので、Visual Studioにインストールします。

marketplace.visualstudio.com

Visual Studio 2017の「ツール」メニュー→「拡張機能と更新プログラム」で開く「拡張機能と更新プログラム」ダイアログで、左のリストから「オンライン」を選び、検索ボックスに「Windows IoT Core Project Templates」と入力し、検索します。

ダイアログの中央のリストに表示された「Windows IoT Core Project Templates for VS 2017」を選び、「ダウンロード」ボタンを押してダウンロードとインストールをします。

バックグラウンド・アプリの作成!

Visual Studioで新しいプロジェクトを作ります。「ファイル」メニュー→「新規作成」→「プロジェクト」で開く「新しいプロジェクト」ダイアログの左のリストの、「インストール済み」→「Visual C#」の下に「Windows IoT Core」という新しいカテゴリーが追加されていますので、これを選択します。 ダイアログの中央のリストの「Background Application (IoT)」を選択し、プロジェクトの名前や場所、ソリューションの名前を設定して、新しいプロジェクトを作ります。

すると、こんなコードが記述されたプロジェクトが出来上がります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;

// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409

namespace BackgroundApplication
{
    public sealed class StartupTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            // 
            // TODO: Insert code to perform background work
            //
            // If you start any asynchronous methods here, prevent the task
            // from closing prematurely by using BackgroundTaskDeferral as
            // described in http://aka.ms/backgroundtaskdeferral
            //
        }
    }
}

このStartupTask.Runメソッドが、アプリの開始時に呼び出され、このメソッドが終了するとアプリも終了します。Mainメソッドみたいなものですね!

非同期!

StartupTask.Runメソッドの中で非同期に実行されるメソッドを呼び出した場合、非同期実行が終了しないうちにRunメソッドが終わってしまうとアプリ自身も終了してしまい、非同期実行は中断されてします。

そこで、テンプレートのコメントにも書いてある「Deferral」を使います。

たとえば、こんな感じ。

using Emmellsoft.IoT.Rpi.SenseHat;
using Windows.ApplicationModel.Background;
using Windows.UI;

namespace BackgroundApplication
{
    public sealed class StartupTask : IBackgroundTask
    {
        // awaitをメソッド内で使うので、Runメソッドにもasyncを付けて非同期に呼び出せるようにする
        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            // Deferralを得る
            BackgroundTaskDeferral deferral = taskInstance.GetDeferral();

            // awaitを使って非同期にGetSenseHatメソッドを実行する
            ISenseHat senseHat = await SenseHatFactory.GetSenseHat();
            // 非同期実行が終了する前に、ここで一旦Runメソッドから抜ける
            // Deferralを取り出しているので、Runメソッドから抜けてもアプリは終了しない

            // 非同期実行が終了すると、ここから実行が再開される(以後のコードは、非同期実行の後処理)
            if (senseHat != null)
            {
                senseHat.Display.Fill(Colors.Red); // Sense HATの全LEDを赤にする
                senseHat.Display.Update(); // Sense HATのLEDの状態を更新する
            }

            // ここまで来たら、アプリが終了してもよい
            // Completeメソッドを呼び出し、非同期実行が終了したことを知らせる
            deferral.Complete();
        }
    }
}

Sense HATのLEDを全て赤にするアプリです。Sense HATを扱うためのパッケージを追加する必要があります。以下の過去記事を参考にしてください!

csharpwhat.hatenablog.com

バックグラウンド・アプリの実行!

プロジェクトを配置すると、Device PortalのApps Managerで表示される一覧に、App Typeが「Background」のアプリとして表示されます。例によって「Actions」ドロップダウンリストから「Start」を選んでアプリを実行できます!

Device Portalで見ていると、Statusがしばらく「Running」になっていますが、そのうち「Stopped」に戻る様子がわかります。