CodeZine(コードジン)

特集ページ一覧

Bing Mapsよりも使いやすい? ComponentOne Studioの地図コンポーネントでストアアプリを作ろう

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2014/10/20 14:00
目次

データ取得ロジックの実装

 サンプルアプリで使用するオープンデータは、Microsoft Azure Mobile Service上で動作しているAED検索オープンデータを使用します 。

リスト1 AEDModel.vb
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Net
Imports System.Runtime.CompilerServices
Imports Newtonsoft.Json

Namespace Models
    Public Class AedInfo
        Public Property Id As Long
        Public Property LocationName As String                '/* 場所_地名【名称】*/
        Public Property FullAddress As String                 '/* 住所_住所【住所】*/
        Public Property Perfecture As String                  '/* 構造化住所_都道府県 */
        Public Property City As String                        '/* 構造化住所_市区町村 */
        Public Property AddressArea As String                 '/* 構造化住所_町名 */
        Public Property AddressCode As String                 '/* 住所コード */
        Public Property Latitude As Single                    '/* 緯度経度座標系_緯度 */
        Public Property Longitude As Single                   '/* 緯度経度座標系_経度 */
        Public Property FacilityId As String                  '/* 公共設備_ID */
        Public Property FacilityName As String                '/* 公共設備_名称 */
        Public Property FacilityPlace As String               '/* 公共設備_設置場所【設置場所】※受付横とか */
        Public Property ScheduleDayType As String             '/* 公共設備_利用可能時間【利用可能時間】 */
        Public Property PhotoOfAedUrl As String               '/* 公共設備_写真URL【写真】 */
        Public Property FacilityNote As String                '/* 公共設備_補足【補足】 */
        Public Property LatLng As Point
    End Class

    Public Class TCity
        Public Property Perfecture As String                  '/* 構造化住所_都道府県 */
        Public Property City As String                        '/* 構造化住所_市区町村 */
        Private _Items = New ObservableCollection(Of AedInfo)
        Public Property Items As ObservableCollection(Of AedInfo)
            Get
                Return Me._Items
            End Get
            Set(value As ObservableCollection(Of AedInfo))
                Me._Items = value
            End Set
        End Property
    End Class

    Public Class AedModel
        Implements INotifyPropertyChanged

        Public Sub New()
        End Sub

        Private _City = New TCity
        Public Property City As TCity
            Get
                Return Me._City
            End Get
            Set(value As TCity)
                Me._City = value
                OnPropertyChanged()
            End Set
        End Property

        Public Async Function SelectData(perfectureName As String, cityName As String) As Task
            Dim targetAeds = New ObservableCollection(Of AedInfo)
            Try
                Dim urlString = String.Format(
                    "https://aed.azure-mobile.net/api/aedinfo/{0}/{1}/",
                    perfectureName,
                    cityName)
                Dim request = CType((WebRequest.Create(urlString)), HttpWebRequest)
                request.Method = "GET"
                request.ContentType = "application/x-www-form-urlencoded"
                Try
                    Dim response = CType((Await request.GetResponseAsync()), HttpWebResponse)
                    Dim responseDataStream = New System.IO.StreamReader(response.GetResponseStream())
                    Dim responseResult = responseDataStream.ReadToEnd()
                    Dim json = JsonConvert.DeserializeObject(Of IEnumerable(Of AedInfo))(responseResult)
                    Dim aeds = From item In json Order By item.FullAddress
                    targetAeds = New ObservableCollection(Of AedInfo)
                    For Each aed In aeds
                        aed.LatLng = New Point(aed.Longitude, aed.Latitude)
                        targetAeds.Add(aed)
                    Next
                Catch ex As Exception
                    OnFaild("NetworkError" + ex.Message)
                End Try
            Catch ex As Exception
                OnFaild("NetworkError" + ex.Message)
            Finally
                Me.City = New TCity With {.Perfecture = perfectureName,
                                          .City = cityName, .Items = targetAeds}
            End Try
        End Function

        Public Event Faild(sender As Object, e As String)
        Protected Sub OnFaild(line As String)
            RaiseEvent Faild(Me, line)
        End Sub

        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
        Protected Sub OnPropertyChanged(<CallerMemberName> Optional propertyName As String = Nothing)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
    End Class
End Namespace

C1Mapsコンポーネントの配置

 ツールボックスからC1MapsコンポーネントをXAMLエディタ上にドラッグ&ドロップします。これだけで必要な参照設定が行われます。

画面デザイン

 サンプル画面の構成は、左に地図、右に一覧表の2カラム構成になっていて、検索ボタンをクリックすると特定市区町村のAED情報を検索表示します。

図4 画面デザイン
図4 画面デザイン
リスト2 MainPage.xaml
        :
     (中略)
        :
<Grid Grid.Row="1" Margin="15,0,0,0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <StackPanel Grid.Column="0" Margin="20,0,20,0">
        <Viewbox VerticalAlignment="Top" HorizontalAlignment="Left">
            <Custom:C1Maps x:Name="C1Maps1" 
                    VerticalAlignment="Top"
                    HorizontalAlignment="Left"
                    Zoom="13"
                    Width="480" Height="600">
                <Custom:C1Maps.Resources>
                    <DataTemplate x:Key="PinStyle">
                        <Custom:C1VectorPlacemark 
                            Fill="Red" Stroke="Red"
                            LabelPosition="Top"
                            Foreground="Red"
                            GeoPoint="{Binding LatLng}"
                            Geometry="M7.4166234,16.197001L13.…(中略)…z">
                            <Custom:C1VectorPlacemark.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
                                    <TranslateTransform Y="-20" X="-10"/>
                                </TransformGroup>
                            </Custom:C1VectorPlacemark.RenderTransform>
                        </Custom:C1VectorPlacemark>
                    </DataTemplate>
                </Custom:C1Maps.Resources>
                <Custom:C1Maps.Source>
                    <Custom:VirtualEarthRoadSource ApplicationId="{x:Null}" />
                </Custom:C1Maps.Source>
                <Custom:C1VectorLayer ItemsSource="{Binding City.Items}"
                                        ItemTemplate="{StaticResource PinStyle}"
                                        LabelVisibility="Visible"/>
            </Custom:C1Maps>
        </Viewbox>
    </StackPanel>
        :
     (中略)
        :

 C1Mapsコンポーネントで緯度経度に合わせてマークを描画するには、

  1. 緯度経度が含まれたコレクションをItemsSourceプロパティにBindingする
  2. マーク描画用スタイルをItemTemplateに指定する
  3. マーク描画用スタイルの中で、C1VectorPlacemarkのGeoPointに緯度経度をBindingする
  4. マーク自体はC1VectorPlacemarkのGeometryで形を指定する

という手順で行います。

 コードビハインド側でループを回して1点1点位置を指定して描画する必要はありません。

検索イベント時のコードの記述

 MainPage.xamlのコードビハインド側に検索用のロジックを一部記載します。

リスト3 MainPage.xaml.vb
Namespace Views
    Public NotInheritable Class MainPage
        Inherits Page
        :
     (中略)
        :
        Public Sub New()
            InitializeComponent()
        :
     (中略)
        :
            Me.DataContext = App.MainVM
        End Sub

        Private Async Sub NavigationHelper_LoadState(sender As Object, e As Common.LoadStateEventArgs)
            Try
                Await App.MainVM.GetItems("愛知県", "豊田市")
                SetCenterPos()
                Me.C1Maps1.Zoom -= 1
                Me.C1Maps1.Zoom += 1
            Catch ex As Exception

            End Try
        :
     (中略)
        :
End Namespace

 NavigationHelper_LoadStateプロシージャの中で、GetItemsメソッドによりデータを取得後にZoomプロパティに-1および+1を実行しているのは、強制的に再描画を発生させて正しく画面が表示されるようにするためです。これは本来不要な処理ですが、ComponentOne Studio 2014 v2では描画方法が変わったのか、このような操作を行わないとマークが画面に表示されません。

 ここまでできたら、後はMainViewModelクラスを記述すれば出来上がりです。

サンプル実行

図5 サンプル実行
図5 サンプル実行

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 初音玲(ハツネアキラ)

     国内SIerのSEでパッケージ製品開発を主に行っており、最近は、空間認識や音声認識などを応用した製品を手掛けています。  個人的には、仕事の内容をさらに拡張したHoloLensなどのMRを中心に活動しています。  Microsoft MVP for Windows Development...

バックナンバー

連載:現役エンジニア直伝! 「現場」で使えるコンポーネント活用術(ComponentOne Studio)

もっと読む

All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5