近くにある病院の場所をキャラクターが音声で教えてくれるアプリを作る

2014年3月17日(月)
薬師寺 国安

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

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

リスト2 (MainWindow.xaml.vb)

01Option Strict On
02 
03‘ コンピュータの地理的位置にアクセスできるようにするクラスの含まれる、Windows.Devices.Geolocation名前空間を
04‘ インポートします。
05Imports Windows.Devices.Geolocation
06 
07‘ Bing Mapsに関するクラスの含まれる、Bing.Maps名前空間をインポートします。
08Imports Bing.Maps
09Imports Windows.UI
10 
11‘ アプリケーションウィンドウやウィンドウ対話を作成し管理するサポートと、ウィンドウ上の入力イベントを処理する
12‘ クラスの含まれる、Windows.UI.Core名前空間をインポートします。
13Imports Windows.UI.Core
14 
15‘ 最新のHTTPアプリケーション用のプログラミング インターフェイスを提供するクラスの含まれる、
16‘ System.Net.Http名前空間をインポートします。
17Imports System.Net.Http
18 
19Imports Windows.UI.Popups
20 
21‘ HospitalInfoクラス内に文字列型の「病院名」、「住所」プロパティを定義しておきます。
22Public Class HospitalInfo
23  Public Property 病院名 As String
24  Public Property 住所 As String
25End Class
26 
27Public NotInheritable Class MainPage
28  Inherits Page
29 
30‘ 現在の地理的位置にアクセスするクラスである、Geolocatorクラスのメンバー変数myGeolocatorを宣言します。
31  Private myGeolocator As Geolocator
32 
33‘ Windowsランタイムコアイベントメッセージディスパッチャを提供するクラスである、
34‘ CoreDispatcherクラスのメンバー変数、myCoreDispacherを宣言します。
35  Private myCoreDispacher As CoreDispatcher
36 
37‘ YahooのアプリケーションIDで初期化された、メンバー定数変数AppIDを宣言します。
38  Const AppID As String = " YahooのアプリケーションID"
39 
40‘ GoogleのAPI Keyで初期化された、メンバー定数変数GoogleAppIDを宣言します。
41  Const GoogleAppID As String = " GoogleのAPI Key"
42  
43  Private flag As Boolean = False
44  Private myCoodinatePosition As String = String.Empty
45  Private myAddressCoodinatePosition As String = String.Empty
46  Private myUri As String = String.Empty
47  Private myAddressLatitude As String
48  Private myAddressLongitude As String
49  Private myAddressUri As String
50 
51‘ MediaElementクラス型のメンバー変数myMediaを宣言します。
52  Private myMedia As MediaElement

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

場所にアクセスし、場所が変更された時や、Geolocatorの機能が変更された時に発生する各イベントで、イベントハンドラを実行するDataShowメソッドを実行します。

1Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
2  DataShow()
3End Sub

場所にアクセスし、場所が変更された時や、Geolocatorの機能が変更された時に発生する各イベントで、イベントハンドラを実行する処理。

myGeolocatorオブジェクトが作成されていない場合は、新しいGeolocatorクラスのインスタンスmyGeolocatorオブジェクトを作成します。
場所認識の精度レベルを表す、DesiredAccuracy プロパティにはDefaultを指定しておきます。
Default以外にHighがありますが、パフォーマンスが低下する恐れがありますので、Defaultを指定しています。

Window.Current.CoreWindow.Dispatcherで、現在アクティブになっている、ウィンドウの内部コアオブジェクトのイベントディスパッチャを取得して、myCoreDispacherで参照します。

AddHandlerステートメントで、場所が更新された時のPositionChangedイベント時のイベントハンドラ、myGeolocator_PositionChangedを追加します。

同じく、AddHandlerステートメントで、更新された場所を提供するGeolocatorの機能が変更された時に発生する、StatusChanged時のイベントハンドラ、myGeolocator_StatusChangedを追加します。

1Private Sub DataShow()
2  If myGeolocator Is Nothing = True Then
3    myGeolocator = New Geolocator
4    myGeolocator.DesiredAccuracy = PositionAccuracy.Default
5    myCoreDispacher = Window.Current.CoreWindow.Dispatcher
6  End If
7  AddHandler myGeolocator.PositionChanged, AddressOf myGeolocator_PositionChanged
8  AddHandler myGeolocator.StatusChanged, AddressOf myGeolocator_StatusChanged
9End Sub

場所が変更された時の処理

myCoreDispacher.RunAsyncメソッドで、イベントディスパッチャを実行し、ディスパッチされたイベントの結果を非同期に返します。ディスパッチャの優先順位は標準のNormalを指定しています。

緯度と経度のデータや都市の住所データを含めることができるGeoPositionクラス型の変数posを宣言し、PositionChangedイベントに関連付けられた場所データを取得します。

Clearメソッドで、地図内を一度クリアしておきます。

新しいPushpinクラスのインスタンスmyPinオブジェクトを作成します。ピンの背景色を「Crimson」に指定します。

新しいLocationクラスのインスタンスmyLocationオブジェクトを作成します。Locationクラスは、地図上の場所の標高と座標値を含むクラスです。

ブール型のメンバー変数flagの値で条件分岐を行います。FlagがTrueであった場合、つまり、マウスを右クリックして表示される住所を入力するボックスに住所を入力して、「OK」ボタンがクリックされた場合、ということです。その場合は、Locationを、メンバー変数myAddressLatitudeに格納された緯度の値と、myAddressLongitudeに格納された経度の値で初期化します。

それ以外の場合は、現在位置の緯度(pos.Coordinate.Point.Position.Latitude)と経度(pos.Coordinate.Point.Position.Longitude)で初期化します。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内にピンの位置を設定します。
myMapにAddメソッドでピンを追加します。
SetViewメソッドで、指定された中心部に位置、ズーム レベル、方位、およびピッチにマップビューを設定します。この場合myLocationの位置に16レベルでズームインします。

ブール型のメンバー変数flagの値で条件分岐を行います。FlagがTrueであった場合、つまり、現在位置の緯度(pos.Coordinate.Point.Position.Latitude)と経度(pos.Coordinate.Point.Position.Longitude)が取得されている場合の処理です。

メンバー変数myAddressUriに「Yahoo!ローカルサーチAPI」のアドレスを格納します。
引数latにpos.Coordinate.Point.Position.Latitudeの緯度の値を指定して、lonにpos.Coordinate.Point.Position.Longitudeの経度の値を指定します。
AppidにはYahooのアプリケーションIDを指定します。

そうでない場合、つまり、マウスを右クリックして表示される住所を入力するボックスに住所を入力して、「OK」ボタンがクリックされた場合、ということです。その場合は、Locationを、メンバー変数myAddressLatitudeに格納された緯度の値と、myAddressLongitudeに格納された経度の値で初期化します。

新しいHttpClientクラスのインスタンスmyAddressHttpClientオブジェクトを作成します。
HttpClientクラスは、URIで識別されるリソースにHTTP要求を送信し、そのリソースからHTTP応答を受信するための基本クラスが含まれています。

XML要素を表すXElementクラス型変数、xmldocを宣言します。

GetStringAsyncメソッドでmyAddressUriの結果を文字列として返し、変数myCurrentAddressに格納します。
GetStringAsyncメソッドは、指定URIにGET要求を送信し、非同期操作で応答本体を文字列として返すメソッドです。

返される文字列はXML形式になっています。このXMLのルート要素には、名前空間や不要な属性が定義されていて、内容を取得する際の邪魔(-_-;)になりますので、Replace関数で、ルート要素()だけに置換しています。

XElement.Parseメソッドで置換された結果のXMLが格納されている、myCurrentAddressを文字列として読み込みます。

読み込んだXMLから

要素の内容を取得して、変数myAddressに格納しておきます。

新しいStackPanelのインスタンスmyAddressStackPanelオブジェクトを作成します。
Marginプロパティに「5」を指定して余白を設けます。
背景色を「Navy」に指定します。
このStackPanelオブジェクトのインスタンスを、非表示としておきます。

新しいTextBlockのインスタンスmyAddressTextBlockオブジェクトを作成します。文字色を「Red」に指定します。
文字サイズに「24」を指定し、パディングに「5」を指定します。
ブール型のメンバー変数flagの値で条件分岐を行います。FlagがFalse であった場合は(つまり通常の処理をしていた場合)、myAddressTextBlockに変数myAddressと文字列「辺り」を連結して表示します。それ以外の場合は、つまり、マウスを右クリックして表示される住所を入力するボックスに住所を入力して、「OK」ボタンがクリックされた場合、ということです。その場合は、WatermarkTextBoxに入力された値と文字列「辺り」を連結して表示します。

myStackPanelオブジェクトにAddメソッドで住所の設定された、myAddressTextBlockを追加します。

SetValueメソッドでmyAddressStackPanelのZIndexPropertyに20を指定します。myAddressStackPanelが前面に表示されます。

ブール型のメンバー変数flagの値で条件分岐を行います。FlagがFalseであった場合、つまり通常の処理を行っていた場合は、MapLayerクラスのSetPositionメソッドで、マップレイヤー内にmyAddressStackPanelオブジェクトの位置を設定し、Locationを現在位置の緯度と経度で初期化して指定します。それ以外の場合、つまり、マウスを右クリックして表示される住所を入力するボックスに住所を入力して、「OK」ボタンがクリックされた場合、ということです。MapLayerクラスのSetPositionメソッドで、マップレイヤー内にmyAddressStackPanelオブジェクトの位置を設定し、Locationをメンバー変数myAddressLatitudeが格納している緯度とmyAddressLongitudeが格納している経度で初期化して設定します。
MapLayerクラスは、地図上の要素の位置を保持しているマップレイヤーを表すクラスです。

myMapにAddメソッドでmyAddressStackPanelオブジェクトを追加します。
myAddressStackPanelは最初の状態では非表示になっているのでわかりませんが、ピンの位置にStackPanelオブジェクトが表示されることになります。

AddHandlerステートメントでピンをタップした時のイベントハンドラを追加します。
イベントハンドラ内では、myAddressStackPanelオブジェクトを表示状態にします。

AddHandlerステートメントでmyAddressStackPanelをタップした時のイベントハンドラを追加します。イベントハンドラ内では、myAddressStackPanelオブジェクトを非表示状態にします。

ブール型のメンバー変数flagの値で条件分岐を行います。FlagがTrueであった場合、つまり、マウスを右クリックして表示される住所を入力するボックスに住所を入力して、「OK」ボタンがクリックされた場合、ということです。

病院の情報を取得するGoogleのWeb APIのURLを設定します。
「location」には緯度と経度をカンマで区切って格納している、メンバー数myAddressCoodinatePositionの値を指定します。
「radius」には範囲(メートル単位)を指定します。ここでは1000を指定して1Kmとしています。
「types」には、何を目的に検索するかを指定します。ここでは「Hospital」を指定しています。
この「types」には|(パイプ)で区切って複数の値を指定できます。指定できる値の一覧は下記のURLを参照してください。
> https://developers.google.com/places/documentation/supported_types

「Sensor」には場所の要求が位置センサー(GPS など)を使用してデバイスから来たかどうかを示す値を、trueまたはfalseで指定します。ここでは「true」を指定しています。
「language」には「ja」を「key」にはGoogleより取得した「APIKey」を指定します。

「OK」ボタンがクリックされていない場合は、locationに現在位置の緯度と経度をカンマで区切った値を格納している、メンバー変数myCoodinatePositionの値を指定します。

検索結果は最大で20件までの情報を取得して表示します。これらの式を変数myUriに格納しておきます。TitleTextBlockにWatermarkTextBlockに入力された値、または現在位置の住所を格納しているmyAddress変数の値と、文字列「辺り」を連結して表示します。

新しいHttpClientのインスタンスmyHttpClientを作成します。
GetStringAsyncメソッドでGoogleの Web APIの式を格納しているmyUriの内容を読み取り、返ってくるXMLを変数resultHospitalに格納します。
XElement.ParseメソッドでresultHospitalが格納しているXMLの内容を、文字列として読み込みます。

HospitalInfoクラス型である新しいリストのインスタンスmyHospitalInfoオブジェクトを作成します。

Descendantsメソッドで、全ての要素の内容を、変数resultに格納しながら、以下の処理を行います。

変数noの値を1ずつ増加させます。この値は、これから作成する「Webで表示」ボタンの、どのボタンがクリックされたかの判定に使用します。

新しいImageのインスタンスmyImageオブジェクトを作成します。Widthに「70」、Heightに「137」と指定し、Sourceプロパティにソリューション・エクスプローラー内のImagesフォルダ内にある「syoko1.png」を指定します。

新しいStackPanelのインスタンスsyokoStackPanelオブジェクトを作成します。背景色に「DarkGreen」を指定し、AddメソッドでmyImageオブジェクトを追加します。

新しいPushPinクラスのインスタンスhospitalPinオブジェクトを作成します。
背景色に「Crimson」を指定し、Textプロパティに1ずつ増加する変数noの値を指定します。
ピンの表面に連番が表示されます。

要素の子要素要素の子要素要素の値を変数myLongitude(経度)に、要素の子要素要素の子要素要素の値を変数myLatitude(緯度)に格納します。
地理的位置に関連付けされた緯度と経度で初期化された、新しいLocationクラスのインスタンスhospitalLocationオブジェクトを作成します。
MapLayerクラスのSetPositionメソッドで、マップレイヤー内に病院のピンの位置を設定します。myMapにAddメソッドで病院の位置にピンを追加します。

新しいStackPanelのインスタンスresultStackPanelオブジェクトを作成し、Orientationに「Horizontal」と指定しておきます。

新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。
Marginに「5」、背景色に「Navy」を指定し、非表示としておきます。

新しいTextBlockのインスタンスmyNameTextBlockを作成します。
文字色は「Red」、Widthに「400」、文字の回り込みは可、文字サイズは「24」、パディングは「5」と指定します。
Textプロパティには、文字列「病院名」と要素の内容を連結して指定します。病院の名前が表示されます。

新しいTextBlockのインスタンスaddressTextBlockを作成します。
文字色は「Beige」、Widthに「400」、文字の回り込みは可、文字サイズは「20」、パディングは「5」と指定します。
Textプロパティには、文字列「住所」と要素の値を連結して表示します。病院の住所が表示されます。

HositalInfoクラスの「病院」プロパティに連番と、要素の値を連結して指定します。「住所」プロパティには要素の値を指定し、AddメソッドでmyHospitalInfoオブジェクトに追加します。

新しいButtonのインスタンスmyButtonを作成します。
Contentプロパティに「Webで表示」と指定します。
Tagプロパティに変数noの値を指定します。どのButtonがクリックされたかの判定に使用します。

キャラクタに読み上げさせる文章の内容をメンバー変数readingAddressに格納しておきます。

SetValueメソッドで、myStackPanelのZIndexPropertyに変数noの値を指定します。myStackPanelがPushPinよりも前面に表示されるようになります。

myStackPanelオブジェクトにAddメソッドで、myNameTextBlock、addressTextBlock、myButtonを追加します。

resultStackPanelオブジェクトに、AddメソッドでmyStackPanelオブジェクト、syokoStackPanelオブジェクトを追加します。
resultStackPanelオブジェクトは非表示としておきます。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内にresultStackPanelの位置を設定します。
myMapにAddメソッドでresultStackPanelを追加します。

AddHandlerステートメントで、病院の位置を表すピンがタップされた時のイベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。
resultStackPanelオブジェクトが表示状態になり、病院の情報とキャラクタが表示されます。
メンバー変数myMediaを、MediaElement1で初期化しておきます。
音声機能へのアクセスを提供する、新しいSpeechSynthesizerのインスタンス、synthオブジェクトを作成します。
SynthesizeTextToStreamAsyncメソッドで、指定した文字列から、音声出力を非同期に生成します。
SetSourceメソッドで、指定されたストリームおよびMIME型を使用してSourceプロパティを設定します。Playメソッドで音声を再生します。
音声にどんな言語で、どのような声で喋らすかは、SpeechSynthesizerのVoiceプロパティで参照できます。下記のURLを参照してください。
> http://msdn.microsoft.com/en-us/library/windows.media.speechsynthesis.speechsynthesizer.voice.aspx
上記URLを見るとJapanese JA は性別が「Female」で、名前は「Haruka」という女性が読み上げるようです。
非同期処理で行われるため、イベントハンドラの先頭にAsyncを追加します。

AddHandlerステートメントで、病院の情報を表示した、resultStackPanelがタップされた時のイベントハンドラを追加します。
音声の読み上げを中止します。resultStackPanelオブジェクトが非表示になります。
AddHandlerステートメントで、Buttonがクリックされた時のイベントハンドラを追加します(Webで表示がクリックされた時の処理です)。
クリックされたButtonのTagの値を変数indexに格納します。数値にキャストしたindexの値をmyIndexに格納します。-1しているのは、ピンの表面に表示される連番は1から20まで表示されますが、XML要素のインデックスは0から始まるため-1しています。

変数mySendAddressにmyIndexに位置する要素の値と、myIndexに位置する要素の値を半角の空白で区切って格納しておきます。住所+半角の空白+病院名の値が格納されます。
これらの値はUri.EscapeDataStringメソッドでエスケープ表現に変換しておきます。
Windows.System.Launcher.LaunchUriAsyncメソッドで、指定されたURIのURIスキーム名に関連付けられている既定のアプリケーション(この場合はIE11のブラウザ)を起動します。

この記述方法では、Windows ストアの認定の要件「2.4 アプリで提供されるプライマリ エクスペリエンスはアプリ内で行われなければならない」に抵触し、ストアの審査には通りませんが、審査員のコメント欄に、「このアプリの目的は病院の位置をBing Maps上に表示させて、キャラクタに読み上げさせることにあります。ブラウザでの表示はあくまでも補助的手段です。」と記述しておけば、大体認定されますので、お試しください。

Try~Catch~End Tryで例外処理を行っています。例外が発生した場合はErrorShowプロシージャを実行します。

最後にGridView1のItemsSourceプロパティにmyHospitalInfoオブジェクトを追加します。これで、マウスの右クリックをした際に、アプリケーションバー内に病院の一覧が表示されます。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。

001  Private Async Sub myGeolocator_PositionChanged(sender As Geolocator, args As PositionChangedEventArgs)
002    Dim myLatitude As String = String.Empty
003    Dim myLongitude As String = String.Empty
004    Dim no As Integer = 0
005  
006    Await myCoreDispacher.RunAsync(CoreDispatcherPriority.Normal, Async Sub()
007      Dim pos As Geoposition = args.Position
008      myMap.Children.Clear()
009  
010      Dim myPin As New Pushpin
011      myPin.Background = New SolidColorBrush(Colors.Crimson)
012   
013      Dim myLocation As Location
014      If flag = True Then
015        myLocation = New Location(CDbl(myAddressLatitude), CDbl(myAddressLongitude))
016      Else
017        'Windows 8.1の新形式
018        myLocation = New Location(CDbl(pos.Coordinate.Point.Position.Latitude), CDbl(pos.Coordinate.Point.Position.Longitude))
019      End If
020        MapLayer.SetPosition(myPin, myLocation)
021        myMap.Children.Add(myPin)
022        myMap.SetView(myLocation, 16)
023         
024      If flag = False Then
025        myAddressUri = String.Format("http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?lat={0}&lon={1}&appid={2}", pos.Coordinate.Point.Position.Latitude, pos.Coordinate.Point.Position.Longitude, AppID)
026      Else
027        myAddressUri = String.Format("http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?lat={0}&lon={1}&appid={2}", myAddressLatitude, myAddressLongitude, AppID)
028      End If
029        Dim myAddressHttpClient As New HttpClient
030        Dim myCurrentAddress As String = String.Empty
031        Dim xmldoc As XElement
032        Try
033          myCurrentAddress = Await myAddressHttpClient.GetStringAsync(myAddressUri)
034          myCurrentAddress = myCurrentAddress.Replace("<YDF firstResultPosition=" & ChrW(34) & "1" & ChrW(34) & " totalResultsAvailable=" & ChrW(34) & "1" & ChrW(34) & " totalResultsReturned=" & ChrW(34) & "1" & ChrW(34) & " xmlns=" & ChrW(34) & "http://olp.yahooapis.jp/ydf/1.0" & ChrW(34) & ">", "<YDF>")
035          xmldoc = XElement.Parse(myCurrentAddress)
036          Dim myAddress = xmldoc.Descendants("Address").Value
037          Dim myAddressStackPanel As New StackPanel
038          myAddressStackPanel.Margin = New Thickness(5)
039          myAddressStackPanel.Background = New SolidColorBrush(Colors.Navy)
040        myAddressStackPanel.Visibility = Xaml.Visibility.Collapsed
041        Dim myAddressTextBlock As New TextBlock
042        myAddressTextBlock.Foreground = New SolidColorBrush(Colors.Red)
043        myAddressTextBlock.FontSize = 24
044        myAddressTextBlock.Padding = New Thickness(5)
045        If flag = False Then
046          myAddressTextBlock.Text = myAddress & " 辺り"
047        Else
048          myAddressTextBlock.Text = WatermarkTextBox1.Text & " 辺り"
049        End If
050        myAddressStackPanel.Children.Add(myAddressTextBlock)
051        myAddressStackPanel.SetValue(Canvas.ZIndexProperty, 20)
052 
053        If flag = False Then
054          'Windows 8.1の新形式
055          MapLayer.SetPosition(myAddressStackPanel, New Location(CDbl(pos.Coordinate.Point.Position.Latitude), CDbl(pos.Coordinate.Point.Position.Longitude)))
056        Else
057          MapLayer.SetPosition(myAddressStackPanel, New Location(CDbl(myAddressLatitude), CDbl(myAddressLongitude)))
058        End If
059        myMap.Children.Add(myAddressStackPanel)
060  
061      AddHandler myPin.Tapped, Sub()
062        myAddressStackPanel.Visibility = Xaml.Visibility.Visible
063      End Sub
064  
065      AddHandler myAddressStackPanel.Tapped, Sub()
066        myAddressStackPanel.Visibility = Xaml.Visibility.Collapsed
067      End Sub
068  
069        If flag = True Then
070          myUri = String.Format("https://maps.googleapis.com/maps/api/place/nearbysearch/xml?location={0}&radius=1000&types=hospital|dentist|doctor&sensor=true&language=ja&key={1}", myAddressCoodinatePosition, GoogleAppID) ‘ (B)
071          TitleTextBlock.Text = WatermarkTextBox1.Text & " 辺りの1Km範囲内の病院を表示"
072        Else
073          myCoodinatePosition = pos.Coordinate.Point.Position.Latitude & "," & pos.Coordinate.Point.Position.Longitude
074          myUri = String.Format("https://maps.googleapis.com/maps/api/place/nearbysearch/xml?location={0}&radius=1000&types=hospital|dentist|doctor&sensor=true&language=ja&key={1}", myCoodinatePosition, GoogleAppID)
075          TitleTextBlock.Text = myAddress & " 辺りの1Km範囲内の病院を表示"
076        End If
077          Dim myHttpClient As New HttpClient
078          Dim resultHospital = Await myHttpClient.GetStringAsync(myUri)
079          Dim httpDoc As XElement = XElement.Parse(resultHospital)
080          Dim myHospitalInfo As New List(Of HospitalInfo)
081          For Each result In From c In httpDoc.Descendants("result") Select c
082            no += 1
083            Dim myImage As New Image
084            With myImage
085              .Width = 70
086              .Height = 137
087              .Stretch = Stretch.UniformToFill
088              .Source = New BitmapImage(New Uri("ms-appx:///Images/syoko1.png", UriKind.Absolute))
089            End With
090            Dim syokoStackPanel As New StackPanel
091            syokoStackPanel.Background = New SolidColorBrush(Colors.DarkGreen)
092            syokoStackPanel.Children.Add(myImage)
093            Dim hospitalPin As New Pushpin
094            hospitalPin.Background = New SolidColorBrush(Colors.Navy)
095            hospitalPin.Text = no.ToString
096  
097            myLongitude = result.Element("geometry").Element("location").Element("lng").Value
098            myLatitude = result.Element("geometry").Element("location").Element("lat").Value
099            Dim hospitalLocation = New Location(CDbl(myLatitude), CDbl(myLongitude))
100            MapLayer.SetPosition(hospitalPin, hospitalLocation)
101            myMap.Children.Add(hospitalPin)
102             
103            Dim resultStackPanel As New StackPanel
104            resultStackPanel.Orientation = Orientation.Horizontal
105            Dim myStackPanel As New StackPanel
106            myStackPanel.Margin = New Thickness(5)
107            myStackPanel.Background = New SolidColorBrush(Colors.Navy)
108            Dim myNameTextBlock As New TextBlock
109            myNameTextBlock.Foreground = New SolidColorBrush(Colors.Red)
110            myNameTextBlock.Width = 400
111            myNameTextBlock.TextWrapping = TextWrapping.Wrap
112            myNameTextBlock.FontSize = 24
113            myNameTextBlock.Padding = New Thickness(5)
114            myNameTextBlock.Text = no.ToString & ":" & "【病院名】=" & result.Element("name").Value
115            Dim addressTextBlock As New TextBlock
116            addressTextBlock.Foreground = New SolidColorBrush(Colors.Beige)
117            addressTextBlock.Width = 400
118            addressTextBlock.TextWrapping = TextWrapping.Wrap
119            addressTextBlock.FontSize = 20
120            addressTextBlock.Padding = New Thickness(5)
121            addressTextBlock.Text = "【住所】=" & result.Element("vicinity").Value
122            myHospitalInfo.Add(New HospitalInfo With {.病院名 = no.ToString & ":【病院名】=" & result.Element("name").Value, .住所 = "【住所】=" & result.Element("vicinity").Value})
123            Dim myButton As New Button
124            With myButton
125              .Content = "Webで表示"
126              .Tag = no.ToString
127            End With
128  
129            Dim readingAddress As String = no.ToString & "ばんめ、病院めいは" & result.Element("name").Value & "です。住所は" & result.Element("vicinity").Value & "です。詳細はウェブで確認してください。"
130          myStackPanel.SetValue(Canvas.ZIndexProperty, no)
131          myStackPanel.Children.Add(myNameTextBlock)
132          myStackPanel.Children.Add(addressTextBlock)
133          myStackPanel.Children.Add(myButton)
134          resultStackPanel.Children.Add(myStackPanel)
135          resultStackPanel.Children.Add(syokoStackPanel)
136          resultStackPanel.Visibility = Xaml.Visibility.Collapsed
137          MapLayer.SetPosition(resultStackPanel, New Location(CDbl(myLatitude), CDbl(myLongitude)))
138        myMap.Children.Add(resultStackPanel)
139        resultStackPanel.SetValue(Canvas.ZIndexProperty, no)
140        AddHandler hospitalPin.Tapped, Async Sub()
141          resultStackPanel.Visibility = Xaml.Visibility.Visible
142          myImage.Visibility = Xaml.Visibility.Visible
143          myMedia = Me.MediaElement1
144          Dim synth = New Windows.Media.SpeechSynthesis.SpeechSynthesizer
145          Dim stream = Await synth.SynthesizeTextToStreamAsync(readingAddress)
146          myMedia.SetSource(stream, stream.ContentType)
147          myMedia.Play()
148        End Sub
149 
150        AddHandler resultStackPanel.Tapped, Sub()
151          myMedia.Stop()
152          resultStackPanel.Visibility = Xaml.Visibility.Collapsed
153        End Sub
154  
155        AddHandler myButton.Click, Async Sub(mySender As Object, myArgs As RoutedEventArgs)
156          Dim index = DirectCast(mySender, Button).Tag
157          Dim myIndex = CInt(index) - 1
158          Dim mySendAddress = httpDoc.Descendants("vicinity")(myIndex).Value & " " & httpDoc.Descendants("name")(myIndex).Value
159          Await Windows.System.Launcher.LaunchUriAsync(New Uri("http://www.bing.com/search?q=" & Uri.EscapeDataString(mySendAddress), UriKind.Absolute))
160        End Sub
161      Next
162        GridView1.ItemsSource = myHospitalInfo
163    Catch
164      ErrorShow()
165  End Try
166        End Sub)
167End Sub
  • 近くの病院をキャラクターが音声で教えてくれるアプリ

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

薬師寺国安事務所代表。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メルマガ会員のサービス内容を見る

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