ユニバーサルWindowsアプリでユーザーデータを保存したり、リソースを解放/取得したりするために使える各種のイベントを紹介する。
powered by Insider.NET
Windowsランタイムアプリ*1では、中断からの再開時に何らかの処理が必要になることがある。例えば、中断時に開放したリソースを再取得するとか、長時間にわたって中断されていた場合にはコンテンツを読み込み直すといった処理である。そのような処理はどう書けばよいのだろうか? また、リソースの解放/再取得については、アプリが切り替えられるときに行わねばならない場合もある。本稿では、両方について解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #99」からダウンロードできる。
*1 このMSDNのWebページは、2014年12月下旬に改訂された。以前は「ストアアプリ」と記述されていた部分が「Windowsランタイムアプリ」に変更されている。
ユニバーサルプロジェクトを使ってユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Community 2013 with Update 4を使っている。
*2 SLAT対応ハードウェアは、Windows Phone 8.1エミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能だ。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウェアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。
*3 事前には「Windows 8.1 Update 1」と呼ばれていたアップデート。スタート画面の右上に検索ボタンが(環境によっては電源ボタンも)表示されるようになるので、適用済みかどうかは簡単に見分けられる。ちなみに公式呼称は「the Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 update that is dated April, 2014」というようである。
*4 Windows Phone 8.1エミュレーターを使用しないのであれば、32bit版のWindows 8.1でもよい。
*5 マイクロソフトのダウンロードページから誰でも入手できる(このURLはUpdate 4のもの)。
*6 本稿に掲載したコードを試すだけなら、無償のExpressエディションやCommunityエディションで構わない。Visual Studio Express 2013 with Update 4 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsランタイムアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。また、昨年11月12日(米国時間)に新しくリリースされたVisual Studio Community 2013 with Update 4(製品版)もマイクロソフトのページから無償で入手できる。Communityエディションは本稿執筆時点では英語版だけなので、同じ場所にあるVisual Studio 2013 Language Packの日本語版を追加インストールし、オプションダイアログで言語を切り替える必要がある。
本稿では、紛らわしくない限り次の略称を用いる。
Visual Studio 2013 Update 2(Update 3/4も)では、残念なことにVB用のユニバーサルプロジェクトのテンプレートは含まれていない*7。そのため、本稿で紹介するVBのコードはユニバーサルプロジェクトではなく、PCL(ポータブルクラスライブラリ)を使ったプロジェクトのものである*8。
*7 VB用のユニバーサルプロジェクトは、今年にリリースされるといわれているVisual Studio 2015(開発コード「Visual Studio 14」)からの提供となるようだ。「Visual Studio UserVoice」(英語)のリクエストに対する、2014年6月18日付けの「Visual Studio team (Product Team, Microsoft)」からの回答による。
*8 Visual Studio 2013 Update 2(またはそれ以降のUpdate)のVBでユニバーサルWindowsアプリを作る場合のお勧めは、「The Visual Basic Team」のブログ記事(英語)によれば、PCLを使う方法のようである。PCLに置いたものは、コードだけでなくXAML(画面)やリソースディクショナリなども共通に利用できる。そこで別途公開のサンプルコードでも、VBはWindows用/Phone用/共通コード(PCL)の3プロジェクト構成とした。ユニバーサルプロジェクトで作らなくてもユニバーサルWindowsアプリはリリースできるのである(「WinRT/Metro TIPS:ユニバーサルプロジェクトで開発するには?」参照)。
アプリが中断/再開されるときに行うべき処理としては、次のようなものがある。
このような処理は、Applicationクラス(Windows.UI.Xaml名前空間)のSuspendingイベント(中断時)/Resumingイベント(再開時)で行えばよい(コンテンツを再取得する場合は、中断時に時刻を記憶しておき、再開時に一定時間以上経過していたら読み込み直すようにするとよい)。これは任意の画面やコントロールで処理できる。ただし、Appクラスでも中断/再開時の処理を行っている場合は、処理の競合に注意が必要だ*9。
例としてユーザーコントロールで処理をする場合は、次のようなコードになる。ここではサンプルということで、リソースの解放/再取得といった処理の代わりに、中断/再開時の時刻を画面へ表示する処理が記述してあると思ってほしい(実際のコードは省略)。
public sealed partial class MyUserControl : UserControl
{
  public MyUserControl()
  {
    this.InitializeComponent();
    // 中断されるときのイベント
    Application.Current.Suspending += Application_Suspending;
    // 中断から再開されたときのイベント
    Application.Current.Resuming += Application_Resuming;
  }
  // 中断されるとき
  private void Application_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
  {
    var deferral = e.SuspendingOperation.GetDeferral();
    SetSuspendTime();
    deferral.Complete();
  }
  // 中断から再開されたとき
  private void Application_Resuming(object sender, object e)
  {
    SetResumeTime();
  }
  private void SetSuspendTime()
  {
    ……省略(現在時刻を画面に表示する)……
  }
  private void SetResumeTime()
  {
    ……省略(現在時刻を画面に表示する)……
  }
}
Public NotInheritable Class MyUserControl
  Inherits UserControl
  Public Sub New()
    InitializeComponent()
    ' 中断されるときのイベント
    AddHandler Application.Current.Suspending, AddressOf Application_Suspending
    ' 中断から再開されたときのイベント
    AddHandler Application.Current.Resuming, AddressOf Application_Resuming
  End Sub
  ' 中断されるとき
  Private Sub Application_Suspending(sender As Object, e As SuspendingEventArgs)
    Dim deferral = e.SuspendingOperation.GetDeferral()
    SetSuspendTime()
    deferral.Complete()
  End Sub
  ' 中断から再開されたとき
  Private Sub Application_Resuming(sender As Object, e As Object)
    SetResumeTime()
  End Sub
  Private Sub SetSuspendTime()
    ……省略(現在時刻を画面に表示する)……
  End Sub
  Private Sub SetResumeTime()
    ……省略(現在時刻を画面に表示する)……
  End Sub
End Class
*9 イベント処理は非同期処理の完了を待ってくれないので、一つのイベントに複数のイベントハンドラーを結び付けると複数の非同期処理が同時に走る可能性がある。スレッド間の排他処理が必要な場合は、「.NET TIPS:非同期:awaitを含むコードをロックするには?(AsyncLock編)[C#、VB]」を参照してほしい。
アプリの切り替え時、すなわち、他のアプリやスタート画面に切り替えられたとき(=自アプリが非表示にされるとき)と他のアプリやスタート画面から自アプリに切り替えられたとき(=自アプリが表示されるとき)に行うべき処理がある。
例えば、カメラやマイクなどといったシステムに一つしかないリソースを使う場合だ。そのようなリソースは、非表示にされるときに他のアプリのために明け渡し、表示されるときに再び取得しなければならない。
このような処理は、Windowクラス(Windows.UI.Xaml名前空間)のVisibilityChangedイベントで行えばよい。任意の画面やコントロールで処理できる。
例としてユーザーコントロールで処理をする場合は、次のようなコードになる。ここではサンプルということで、前と同様に省略してあるが非表示/表示時の時刻を画面へ表示する処理が記述してあると思ってほしい。
public sealed partial class MyUserControl : UserControl
{
  public MyUserControl()
  {
    this.InitializeComponent();
    // ウィンドウの表示/非表示が切り替わったときのイベント
    Window.Current.VisibilityChanged += Window_VisibilityChanged;
  }
  // ウィンドウの表示/非表示が切り替わったとき
  private void Window_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs e)
  {
    if (!e.Visible)
    {
      // 非表示にされるとき
      SetHideTime();
      e.Handled = true;
    }
    else
    {
      // 表示されるとき
      SetShowTime();
      e.Handled = true;
    }
  }
  private void SetHideTime()
  {
    ……省略(現在時刻を画面に表示する)……
  }
  private void SetShowTime()
  {
    ……省略(現在時刻を画面に表示する)……
  }
}
Public NotInheritable Class MyUserControl
  Inherits UserControl
  Public Sub New()
    InitializeComponent()
    ' ウィンドウの表示/非表示が切り替わったときのイベント
    AddHandler Window.Current.VisibilityChanged, AddressOf Window_VisibilityChanged
  End Sub
  ' ウィンドウの表示/非表示が切り替わったとき
  Private Sub Window_VisibilityChanged(sender As Object, e As Windows.UI.Core.VisibilityChangedEventArgs)
    If (Not e.Visible) Then
      ' 非表示にされるとき
      SetHideTime()
      e.Handled = True
    Else
      ' 表示されるとき
      SetShowTime()
      e.Handled = True
    End If
  End Sub
  Private Sub SetHideTime()
    ……省略(現在時刻を画面に表示する)……
  End Sub
  Private Sub SetShowTime()
    ……省略(現在時刻を画面に表示する)……
  End Sub
End Class
以上の二つのコードをともに実装し、実行してみると以下のような結果になる(次からの画像)。これには、説明していないカメラのプレビューを表示する処理も入っている(別途公開のサンプルコードには含まれている)。それぞれの処理を行った時刻の表示に着目してほしい。
 アプリを起動したとき(Windows Phone 8.1)
アプリを起動したとき(Windows Phone 8.1) アプリを切り替えたとき(Windows Phone 8.1)
アプリを切り替えたとき(Windows Phone 8.1) 中断/再開したとき(Windows Phone 8.1)
中断/再開したとき(Windows Phone 8.1)中断からの再開時にコンテンツを再取得するような処理は、ApplicationクラスのResumingイベントで行う。リソースを解放/再取得する処理は、そのタイプによって、ApplicationクラスのSuspendingイベント/Resumingイベント(中断/再開時)か、WindowクラスのVisibilityChangedイベント(非表示/表示時)を利用するとよい。
Copyright© Digital Advantage Corp. All Rights Reserved.