Windows 8は当然マルチタスクのOSですが、
Windowsストアアプリケーションは多くて同時に2つまでしかアプリを実行できません(MetroStyleApp入門 vol14.snap app参照)。
それでは、バックグラウンドにまわったアプリケーションは処理を実行する手段が無いのかというと、そうではありません。
限定的ではありますが、バックグラウンドで処理を実行する方法があります。今回はその紹介第一回目。
まずは実行して動かしてみるところまで。
バックグラウンドで処理を実行する条件は色々あるのですが、タイマー処理が最短で15分後など、開発時に即座に動作できるものがあまりありません。
参考サイトなどで良く書かれている「タイムゾーンが変わったタイミングで実行」というのが一番手っ取り早く確認できる方法なので、今回もそのイベントを利用します。
(ちゃんと動作が確認するまでに何度タイムゾーンを変更したことか・・・)
バックグラウンドタスクを実行すには大きく以下のプロセスが必要です
・バックグラウンドタスクの実装をする
・バックグラウンドタスクの登録処理をする
・バックグラウンドタスクを利用するようにマニフェストファイルに記述する
RC状態だからかもしれませんが、このプロセスで幾つかエラーも出ずに処理が実行されないケースがあり手間取りました。
それではさっそくバックグラウンドタスクを実装していきましょう。
プロジェクトを作成したら、そこにタスク用の新しいプロジェクトを追加します。
「追加」→「新しいプロジェクト」
「ClassLibrary」の名前を「SampleTask(任意)」で作成。
ここでハマリどころ追加したプロジェクトで右クリック「プロパティ」→「出力の種類」を「Windowsランタイムコンポーネント」に変更するのを忘れずに。
プロジェクト作成時に追加されたClass1.csを以下のように編集。
public sealed class Class1 : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode("Toast Title"));
toastTextElements[1].AppendChild(toastXml.CreateTextNode("Toast Description"));
ToastNotification toast = new ToastNotification(toastXml);
toast.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(30);
toast.Failed += toast_Failed;
ToastNotificationManager.CreateToastNotifier().Show(toast);
deferral.Complete();
return;
}
void toast_Failed(ToastNotification sender, ToastFailedEventArgs args)
{
throw new NotImplementedException();
}
}
タスクとして利用するクラスはIBackgroundTaskをインプリメントしている必要があります。
IBackgroundTaskはRunメソッドを一つ実装する必要があります。これがタスクとして実行される処理です。
今回はトースト通知を出すことにしました。
最後に忘れずにメインのプロジェクトの参照に追加したSampleTaskプロジェクトを追加しましょう。
続いて、用意したタスクを呼び出す処理を記述します。
MainPage.xaml.csに以下のように記述します。
public BackgroundTaskRegistration regist;
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// 先に登録されたタスクをいったん削除する
if (BackgroundTaskRegistration.AllTasks.Count > 1)
{
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
task.Value.Unregister(true);
}
}
// トリガーはタイムゾーンが変更されたとき
SystemTrigger trigger = new SystemTrigger(SystemTriggerType.TimeZoneChange, true);
var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.Name = "SampleTask"; // タスクの名前(任意)
taskBuilder.TaskEntryPoint = "SampleTask.Class1"; // 実行するモジュール名(名前空間.ファイル名)
taskBuilder.SetTrigger(trigger);
regist = taskBuilder.Register();
regist.Completed += regist_Completed;
regist.Progress += regist_Progress;
}
void regist_Progress(BackgroundTaskRegistration sender, BackgroundTaskProgressEventArgs args)
{
}
void regist_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
}
TaskEntryPointでしばらく悩みました。
クラスを指定していたんですが、それにしては文字列指定は変だよなぁと思いながらようやく正解にたどり着きました。
あとは、マニフェストにバックグラウンドタスクを追加するだけです。
Package.appxmanifestの宣言タブにバックグラウンドタスクを追加します。
エントリポイントにはプログラムで指定したものと同じ文字列を与えます。
今回はトースト通知を出すので、アプリケーションUIのトースト対応も「はい」にしておきます。
実際に実行してみましょう。
バックグラウンドタスクのトリガーはタイムゾーンの変更でした。
Windows8のタスクバーの時計の部分をクリックして、時間を変更します。
「日付と時刻の設定の変更…」をクリック。
「タイムゾーンの変更」で今選んでいるタイムゾーンと別のものを選んでみましょう。
数秒後にトースト通知が表示されれば成功です。
バックグラウンドタスクにはロックスクリーンに表示するものや、他のトリガーで起動するものがあります。
次回以降でバックグラウンドタスクに触れる際ははその辺を解説していきたいと思います。
(次回はトースト通知の予定)
クイック スタート: バックグラウンド タスクの作成と登録 (C#/VB/C++ と XAML を使った Metro スタイル アプリ)
バックグラウンド タスクによるアプリのサポート (C#/VB/C++ と XAML を使った Metro スタイル アプリ)
アプリケーション マニフェストでバックグラウンド タスクを宣言する方法 (C#/VB/C++ と XAML を使った Metro スタイル アプリ)
Please give us your valuable comment