連載
» 2014年03月13日 17時15分 公開

WinRT/Metro TIPS:カレンダーアプリに予定を入れるには?[Windows 8.1ストアアプリ開発]

Win 8.1で追加された新しいコントラクトを利用すると、カレンダーアプリに予定を入れられる。カレンダーへの予定追加と更新の方法を説明する。

[山本康彦(http://www.bluewatersoft.jp/),BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次

 カレンダーアプリに予定を入れたいと思ったことはないだろうか? 例えば、イベントの予約をするアプリで、予約の完了と同時にそのイベントの予定をカレンダーに入れたいといった場合だ。Windows 8.1(以降、Win 8.1)で追加された新しいコントラクトを利用すると、それが可能になる。本稿では、新しいコントラクトを紹介した後、新しい予定を作ってカレンダーに入れ、またそれを更新する方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #66(Windows 8.1版)」からダウンロードできる。

事前準備

 Win 8.1用のWindowsストアアプリを開発するには、Win 8.1とVisual Studio 2013(以降、VS 2013)が必要である。本稿ではOracle VM VirtualBox上で64bit版Windows 8.1 Pro(日本語版)とVisual Studio Express 2013 for Windows(日本語版)*1を使用している。

*1 マイクロソフト公式ダウンロードセンターの「Microsoft Visual Studio Express 2013 for Windows」から無償で入手できる。


新しい2つのコントラクト

 共有やファイルピッカーなどのコントラクトは、すでにおなじみだろう。Win 8.1では、予定(Appointment)と連絡先(Contact)のコントラクトが新しく追加された(次の画像)。カレンダーアプリに予定を入れるには、予定コントラクトを用いる。

予定コントラクトの動作概要図
連絡先コントラクトの動作概要図 予定コントラクト(上)と連絡先コントラクト(下)の動作概要図
Build 2013におけるプレゼンテーション「Building Apps That Integrate with People and Events」(2013/6/27)の資料より抜粋。本稿では扱わないが、標準の連絡先プロバイダー(=Win 8.1の「ピープル」アプリ)が表示する連絡先カード(Contact card)からは、メールを送信したりSkypeで電話をかけたりできる。 なお、Windows 8から存在している連絡先ピッカー(Windows.ApplicationModel.Contacts.Provider名前空間)と、この新設された連絡先プロバイダーは別のものである。

 予定を管理するアプリ(=カレンダーアプリ)は「予定プロバイダー」と呼ばれ、連絡先を管理するアプリは「連絡先プロバイダー」と呼ばれる。これらのプロバイダーアプリを作るには、マニフェストで「デバイス機能」の宣言が必要になる(VS 2013のGUIからは設定できない)。カレンダーアプリに予定を入れる側のアプリには、宣言は不要だ。

 さて、本稿では予定のコントラクトを利用する。予定プロバイダーは、Win 8.1に標準の「カレンダー」アプリが実装している。予定のコントラクトと予定プロバイダーを使うと、予定の追加、置き換え、そして予定の表示(正確には、予定が入っている付近の日時の表示)が可能だ。次の画像の左半分は本稿のために作成したアプリで、予定をカレンダーアプリに追加しようとしているところ。右半分はカレンダーアプリで、追加された予定の辺りのカレンダーを表示しているところである。

本稿で作成したアプリを実行している画面 本稿で作成したアプリを実行している画面
左側のアプリから、右側のカレンダーアプリに予定を追加し、その予定の付近を表示させている。 左側のアプリでは、さらに同じ予定を追加しようとしていて、フライアウトが出ている(このまま[追加]ボタンをタップすると、右側に予定がもう1つ重複して登録されてしまう)。 なお、共有コントラクトや印刷コントラクトなどでは画面の右端から大きなフライアウトが出てくるが、新しく追加された予定と連絡先ではこのように画面内に小さなフライアウトが出る。

UIを作成する

 本稿ではXAMLコードの解説はしないので、次の図を参考にして適宜UIを作成してほしい。なお、TextBoxコントロール(Windows.UI.Xaml.Controls名前空間)に指定してあるMaxLengthプロパティの値は、予定プロバイダーが受け取り可能な最大長である。

本稿のために作成したアプリのUI 本稿のために作成したアプリのUI

カレンダーアプリに予定を追加するには?

 予定を表すAppointmentオブジェクト(Windows.ApplicationModel.Appointments名前空間)を作り、AppointmentManagerクラス(Windows.ApplicationModel.Appointments名前空間)のShowAddAppointmentAsyncメソッドを呼び出せばよい。ただし、ShowAddAppointmentAsyncメソッドを呼び出すときに、フライアウトを表示する基準位置を指定する必要がある。

 まず、予定を表すAppointmentオブジェクトは、次に示すメソッドのようにして作成する。

private Windows.ApplicationModel.Appointments.Appointment CreateAppointment()
{
  var appointment = new Windows.ApplicationModel.Appointments.Appointment();

  // 件名
  appointment.Subject = subjectTextBox.Text;

  // 開始日時
  DateTimeOffset date = datePicker1.Date;
  TimeSpan start = timePicker1.Time;
  appointment.StartTime = date.Add(start);

  // 継続時間
  TimeSpan end = timePicker2.Time;
  appointment.Duration = end.Subtract(start);

  // 場所
  appointment.Location = locationTextBox.Text;

  // 詳細
  appointment.Details = detailsTextBox.Text;

  return appointment;
}

Private Function CreateAppointment() _
                 As Windows.ApplicationModel.Appointments.Appointment

  Dim appointment = New Windows.ApplicationModel.Appointments.Appointment()

  ' 件名
  appointment.Subject = subjectTextBox.Text

  ' 開始日時
  Dim appointmentDate As DateTimeOffset = datePicker1.Date
  Dim start As TimeSpan = timePicker1.Time
  appointment.StartTime = appointmentDate.Add(start)

  ' 継続時間
  Dim endTime As TimeSpan = timePicker2.Time
  appointment.Duration = endTime.Subtract(start)

  ' 場所
  appointment.Location = locationTextBox.Text

  ' 詳細
  appointment.Details = detailsTextBox.Text

  Return appointment
End Function

Appointmentオブジェクトを作成するメソッド(上:C#、下:VB)
MainPage.xaml.csファイルにこのコードを追加する。この他にも多くの情報を追加できる。詳細はMSDNの「Appointment class」を参照。

 次に、フライアウトを表示する基準位置は、タップされたボタンにしよう。ボタンなどのFrameworkElementオブジェクト(Windows.UI.Xaml名前空間)の位置とサイズを取得するコードは次のメソッドのように書ける。

private Windows.Foundation.Rect GetElementRect(FrameworkElement element)
{
  var buttonTransform = element.TransformToVisual(null);
  var point = buttonTransform.TransformPoint(new Windows.Foundation.Point());
  var size = new Windows.Foundation.Size(element.ActualWidth, element.ActualHeight);
  return new Windows.Foundation.Rect(point, size);
}

Private Function GetElementRect(element As FrameworkElement) _
                 As Windows.Foundation.Rect
  Dim buttonTransform = element.TransformToVisual(Nothing)
  Dim point = buttonTransform.TransformPoint(New Windows.Foundation.Point())
  Dim size = New Windows.Foundation.Size(element.ActualWidth, element.ActualHeight)
  Return New Windows.Foundation.Rect(point, size)
End Function

コントロールの位置とサイズを取得するメソッド(上:C#、下:VB)

 最後に、ShowAddAppointmentAsyncメソッドの呼び出しを合わせて、ボタンのクリックイベントにまとめる(次のコード)。

private async void registerButton_Click(object sender, RoutedEventArgs e)
{
  // 予定のオブジェクトを作る
  var appointment = CreateAppointment();

  // フライアウトを表示するターゲット(=ボタン)の位置とサイズ
  var rect = GetElementRect(sender as FrameworkElement);

  // 予定を登録するフライアウトを出す
  var appointmentId
    = await Windows.ApplicationModel.Appointments.AppointmentManager
            .ShowAddAppointmentAsync(appointment, rect, 
                                     Windows.UI.Popups.Placement.Default);
}

Private Async Sub registerButton_Click(sender As Object, e As RoutedEventArgs)

  ' 予定のオブジェクトを作る
  Dim appointment = CreateAppointment()

  ' フライアウトを表示するターゲット(=ボタン)の位置とサイズ
  Dim rect = GetElementRect(sender)

  ' 予定を登録するフライアウトを出す
  Dim appointmentId _
    = Await Windows.ApplicationModel.Appointments.AppointmentManager _
            .ShowAddAppointmentAsync(appointment, rect, _
                                     Windows.UI.Popups.Placement.Default)
End Sub

予定を作ってカレンダーアプリに登録するフライアウトを出すコード(上:C#、下:VB)
非同期メソッドの呼び出しをしているので、メソッドのシグネチャにasync/Asyncキーワードが必要だ。 なお、このコードではappointmentId変数を使っていないが、ShowAddAppointmentAsyncメソッドの呼び出し後にappointmentId変数が空文字列だったら予定の追加に失敗したと判定できる。

 ここで注意すべきは、ShowAddAppointmentAsyncメソッドを呼び出しても、予定はカレンダーに登録されず、予定をカレンダーアプリに登録するためのフライアウトが表示されるだけであることだ。フライアウトの下部にある[追加]ボタンをエンドユーザーがタップしたときに、実際にカレンダーアプリに予定が追加されるのである。そして、カレンダーアプリが予定の追加に成功すると、1文字以上の文字列(「予定ID」)がShowAddAppointmentAsyncメソッドから返ってくる。エンドユーザーが[追加]ボタンをタップせずにフライアウトを閉じたり、タップしてもカレンダーアプリ側で予定の追加に失敗したりすると、空文字列(=String.Empty)が返される。

カレンダーアプリに予定を表示させるには?

 AppointmentManagerクラスのShowTimeFrameAsyncメソッドを呼び出せばよい(次のコード)。それだけで、カレンダーアプリが起動して、指定日時前後のカレンダーが表示される。横置き画面の場合は、先に載せた画像のように自動的に画面が分割され、呼び出し元のアプリとカレンダーアプリが並んで表示される。

private async void registerButton_Click(object sender, RoutedEventArgs e)
{
  // 予定のオブジェクトを作る
  var appointment = CreateAppointment();
  // フライアウトを表示するターゲット(=ボタン)の位置とサイズ
  var rect = GetElementRect(sender as FrameworkElement);
  // 予定を登録するフライアウトを出す
  var appointmentId
    = await Windows.ApplicationModel.Appointments.AppointmentManager
            .ShowAddAppointmentAsync(appointment, rect, 
                                     Windows.UI.Popups.Placement.Default);

  if (!string.IsNullOrEmpty(appointmentId)) // 予定の登録に成功した場合
  {
    // カレンダーアプリを表示する
    var timeToShow = appointment.StartTime; // 表示させたい日時
    var duration = TimeSpan.FromDays(1.0);  // 表示させたい時間範囲の目安
    await Windows.ApplicationModel.Appointments.AppointmentManager
          .ShowTimeFrameAsync(timeToShow, duration);
  }
}

Private Async Sub registerButton_Click(sender As Object, e As RoutedEventArgs)
  ' 予定のオブジェクトを作る
  Dim appointment = CreateAppointment()
  ' フライアウトを表示するターゲット(=ボタン)の位置とサイズ
  Dim rect = GetElementRect(sender)
  ' 予定を登録するフライアウトを出す
  Dim appointmentId _
    = Await Windows.ApplicationModel.Appointments.AppointmentManager _
            .ShowAddAppointmentAsync(appointment, rect, _
                                     Windows.UI.Popups.Placement.Default)

  If (Not String.IsNullOrEmpty(appointmentId)) Then ' 予定の登録に成功した場合
    ' カレンダーアプリを表示する
    Dim timeToShow = appointment.StartTime ' 表示させたい日時
    Dim duration = TimeSpan.FromDays(1.0)  ' 表示させたい時間範囲の目安
    Await Windows.ApplicationModel.Appointments.AppointmentManager _
          .ShowTimeFrameAsync(timeToShow, duration)
  End If
End Sub

予定の登録に成功したときにカレンダーアプリを表示するコード(上:C#、下:VB)
太字の部分を追加する。予定の登録に成功したときに、カレンダーアプリが表示される。
なお、実際に表示される範囲は、duration引数に基づいてカレンダーアプリが決定する。

カレンダーアプリの予定を更新するには?

 AppointmentManagerクラスのShowReplaceAppointmentAsyncメソッドを使う。予定を追加するときのShowAddAppointmentAsyncメソッドとの違いは、既存の予定を識別するための予定IDも引数として渡すことだ(次のコード)。実際のアプリでは、予定IDを保存し管理するロジックを作り込む必要がある。

private async void registerButton_Click(object sender, RoutedEventArgs e)
{
  // 登録済みの予定IDを取得する
  var appointmentId = ……省略……

  // 新しい予定のオブジェクトを作る
  var appointment = CreateAppointment();

  // フライアウトを表示するターゲット(=ボタン)の位置とサイズ
  var rect = GetElementRect(sender as FrameworkElement);

  // 予定を更新するフライアウトを出す
  var newAppointmentId
    = await Windows.ApplicationModel.Appointments.AppointmentManager
            .ShowReplaceAppointmentAsync(appointmentId, appointment, rect, 
                                         Windows.UI.Popups.Placement.Default);
}

Private Async Sub registerButton_Click(sender As Object, e As RoutedEventArgs)

  ' 登録済みの予定IDを取得する
  Dim appointmentId = ……省略……

  ' 新しい予定のオブジェクトを作る
  Dim appointment = CreateAppointment()

  ' フライアウトを表示するターゲット(=ボタン)の位置とサイズ
  Dim rect = GetElementRect(sender)

  ' 予定を更新するフライアウトを出す
  Dim newAppointmentId _
    = Await Windows.ApplicationModel.Appointments.AppointmentManager _
            .ShowReplaceAppointmentAsync(appointmentId, appointment, rect, _
                                         Windows.UI.Popups.Placement.Default)
End Sub

既存の予定を置き換えるコード(上:C#、下:VB)
ここで使っているappointmentIdは、予定を追加したときの返値を保存しておいたもの。予定の更新に成功したときのnewAppointmentIdは、元のappointmentIdとは異なっている可能性があるので注意。

 ShowReplaceAppointmentAsyncメソッドも、予定を更新するフライアウトを出すだけであり、実際に更新されるかどうかはShowAddAppointmentAsyncメソッドと同様である。なお、本稿では紹介しなかったが、予定を削除するためのShowRemoveAppointmentAsyncメソッドもある。

まとめ

 AppointmentManagerクラスを使って、カレンダーアプリに予定を追加したり更新したりできる。また、カレンダーアプリに任意の日時を表示させることも可能だ。

 予定コントラクトについては、次のドキュメントも参照してほしい。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。