キャラクターが声で天気予報を教えてくれるアプリを作る

2014年2月26日(水)
薬師寺 国安

次に、ソリューション・エクスプローラー内のBingMapsPage.xamlを展開して表示される、BingMapsPage.xaml.vbをダブルクリックしてリスト5のコードを記述します。

ロジックコードを記述する

リスト5 (BingMapsPage.xaml.vb)

Imports System.Net.Http

‘ Bing Mapsに関するクラスの含まれるBing.Maps名前空間を読み込みます。

Imports Bing.Maps

Imports Windows.UI
Imports Windows.UI.Popups

‘ TenkiInfoクラス内に文字列型の「日付」、「天気」、「画像」、「最高気温」、「最低気温」プロパティを定義しておきます。

Public Class TenkiInfo
  Public Property 日付 As String
  Public Property 天気 As String
  Public Property 画像 As String
  Public Property 最高気温 As String
  Public Property 最低気温 As String
End Class
Public NotInheritable Class BingMapsPage
  Inherits Page

‘ 選択した都道府県のURIを格納するメンバー変数myUriを宣言します。

  Private myUri As String

‘ 「地域」のデータを格納するメンバー変数areaDataを宣言します。

  Private areaData As String

‘ 緯度のデータを格納するmyLatitudeメンバー変数を宣言します。

  Private myLatitude As String

‘ 経度のデータを格納するメンバー変数myLongitudeを宣言します。

  Private myLongitude As String

  Private no As Integer = 0

‘ HttpClientクラス型のメンバー変数myHttpClientを宣言します。

  Private myHttpClient As HttpClient

  Private resultXml As String

‘ XML要素を表すXElementクラス型のメンバー変数xmldocを宣言します。

  Private xmldoc As XElement

‘ 指定したコレクションに対する単純な反復処理をサポートする列挙子である、
‘ インターフェイス型のメンバー変数queryを宣言します。

  Private query As IEnumerable(Of System.Xml.Linq.XElement)

‘ 新しいPushPinクラスのインスタンスである、myPinメンバー変数を宣言します。

  Private myPin As New Pushpin
  Private myInfoCount As Integer

‘ TextBlockクラス型のmyDateTextBlockとmyTenkiTextBlockメンバー変数を宣言します。

  Private myDateTextBlock As TextBlock
  Private myTenkiTextBlock As TextBlock

‘ Imageクラス型のメンバー変数myImageを宣言します。
 
  Private myImage As Image

‘ TextBlockクラス型のメンバー変数、maxTextBlcokとminTextBlockを宣言します。
‘ 最高気温の値と最低気温の値が格納されます。

  Private maxTextBlock As TextBlock
  Private minTextBlock As TextBlock

‘ StackPaneクラス型のメンバー変数myTenkiStackPanelメンバー変数を宣言します。

  Private myTenkiStackPanel As StackPanel

‘ Buttonクラス型のメンバー変数nextButtonとprevButtonメンバー変数を宣言します。

  Private nextButton As Button
  Private prevButton As Button

‘ キャラクターが読み上げる内容を格納するメンバー変数readingTenkiを宣言します。

  Private readingTenki As String

ページがアクティブになった時の処理

MainPageから送られてきた値をe.Parameterで受け取ります。Object型であるため、DirectCastで文字列にキャストします。

送られてきたデータは都道府県のURIと地域名がカンマで区切られて送られてきていますので、Split関数で分解し、配列変数myDataに格納します。

メンバー変数myUriには、配列変数myData(0)の値を格納します。都道府県のURIが格納されます。

メンバー変数areaDataには、配列変数myData(1)の値を格納します。「地域名」が格納されます。

新しいHttpClientのインスタンスmyHttpClientオブジェクトを作成し、GetStringAsyncメソッドで、指定したURIにGET要求を送信し、非同期操作で応答本体を文字列として受け取り、メンバー変数resultXmlに格納します。

XElement.ParseメソッドでresultXmlの値を文字列として読み込みます。

要素の属性”id”がメンバー変数areaDataと同じである要素を選択するクエリを定義します。
PushPinの背景色を「Crimson」に指定し、枠線を「3」に枠線の色を「Navy」に指定しておきます。

メンバー変数myLatitudeに要素の子要素の値を格納します。

メンバー変数myLongitudeには要素の子要素の値を格納します。

これらXMLの構造については図7を参照してください。

myLatitudeやmyLongitudeの値が空であった場合は、警告メッセージを発して処理を抜けます。そうでない場合は、新しいLocationのインスタンスを作成し、myLatutudeとmyLonditudeで初期化し、変数myLocationで参照します。

MapLayer.SetPosition(myPin, myLocation)

と指定すると、指定した緯度、経度の位置にピンが立ちます。

myMapにmyPinオブジェクトを追加します。

SetViewメソッドでmyLocationの位置にズームインします。

TenkiInfoクラスの新しいリストであるmyTenkiInfoオブジェクトを作成します。

TenkiInfoクラスの「日付」プロパティに要素内にある要素の属性”date”の値を指定します。
「天気」プロパティには要素の値を、「画像」プロパティには要素の値を、「最高気温」プロパティには、要素の子要素要素でインデックスが0の値を指定します。
「最低気温」プロパティには要素の子要素要素でインデックスが1の値を指定し、AddメソッドでmyTenkiInfoオブジェクトに追加します。

GridView1のItemsSourceプロパティにmyTenkiInfoオブジェクトを指定します。これでマウスの右クリックをすると、アプリケーションバー内に天気予報の一覧が表示されます。

ピンの位置に今日の天気予報を表示するDataShowタスクを実行します。

  Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)

    Dim getMapsData As String = DirectCast(e.Parameter, String)
    Dim myData() As String = getMapsData.Split(CChar(","))
    myUri = myData(0)
    areaData = myData(1)
    myHttpClient = New HttpClient
    resultXml = Await myHttpClient.GetStringAsync(myUri)
    xmldoc = XElement.Parse(resultXml)
    query = From c In xmldoc.Descendants("area") Where c.Attribute("id").Value.Equals(areaData) Select c
 
    myPin.Background = New SolidColorBrush(Colors.Crimson)
    myPin.BorderThickness = New Thickness(3)
    myPin.BorderBrush = New SolidColorBrush(Colors.Navy)
 
    myLatitude = query.Descendants("geo").Elements("lat").Value
    myLongitude = query.Descendants("geo").Elements("long").Value
    If myLatitude = String.Empty AndAlso myLongitude = String.Empty Then
      Dim message = New MessageDialog("緯度、経度が設定されていませんので、表示できません。")
      Await message.ShowAsync
      Exit Sub
    Else
      Dim myLocation = New Location(CDbl(myLatitude), CDbl(myLongitude))
      MapLayer.SetPosition(myPin, myLocation)
      myMap.Children.Add(myPin)
      myMap.SetView(myLocation, 10)

    End If

      Dim myTenkiInfo As New List(Of TenkiInfo)

      For Each result In query
        For Each result2 In result.Descendants("info")
          With myTenkiInfo
  .Add(New TenkiInfo With {.日付 = CStr(result2.Attributes("date").First), _
                           .天気 = result2.Elements("weather").Value, _
                           .画像 = result2.Elements("img").Value, _
                           .最高気温 = result2.Elements("temperature").Elements("range")(0).Value & "℃", _
                           .最低気温 = result2.Elements("temperature").Elements("range")(1).Value})
          End With
        Next
      Next
      GridView1.ItemsSource = myTenkiInfo
      Await DataShow()
    End Sub
  • キャラクター音声天気予報アプリのサンプル

    『Windows 8.1+Visual Studio 2013によるWindows ストア・アプリ開発実例集』 第8回のサンプルプログラムです。
薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています