Visual Basicでユニバーサルアプリに挑戦!

2014年8月6日(水)
薬師寺 国安

App1_Common(移植可能)プロジェクト内にMainPage.xamlを作成

ソリューションエクスプローラー内の「App1_Common(移植可能)」を選択し、マウスの右クリックメニューから[追加]ー[新しい項目]と選択します。表示される画面から[XAML]を選択し、「空白のページ」テンプレートを選択します。[名前]には「MainPage.xaml」と指定します(図11)。

図11:[XAML]から「空白のページ」を選択(クリックで拡大)

[追加]ボタンをクリックします。すると、ソリューションエクスプローラー内の「App1_Common(移植可能)」プロジェクト内に「MainPage.xaml」と「MainPage.xaml.vb」が作成されます。この中にコードを記述します。

「Windows 8.1」か「Windows Phone 8.1」か、どちらをメインにコードを記述していくかは、図12で選択ができます。今回は、「Windows Phone 8.1」をメインにコードを書いていきます。「Windows 8.1」をメインにコードを記述すると、解像度の違いで、「Windows Phone 8.1」で実行した際、画面が極端に小さく表示されるからです。

図12:コードのメインを「Windows 8.1」か「Windows Phone 8.1」かの、どちらに記述するかを選択できる。ここでは「Windows Phone 8.1」を選択しているが、デフォルトが「「Windows Phone 8.1」になっている(クリックで拡大)

先にも書いたように、デフォルトでは「Windows Phone 8.1」のデザイン画面と、XAMLコード画面が表示されます(図13)。

図13:デフォルトでは「Windows Phone 8.1」が表示される(クリックで拡大)

では、この画面にツールボックスからコントロールを配置していきましょう。

コントロールの配置

デザイン画面上に配置するコントロール名とその名前は表1のようになります。

コントロール名 名前
TextBlock 名前なし。「郵便番号検索」のタイトル
TextBox TextBox1
ListBox resultListBox
AppbarButton okButton
表1:配置するコントロールとその名前

全てをレイアウトすると図14のようになります。

図14:表1のコントロールを配置した(クリックで拡大)

書き出されるXAMLコードをリスト1のように編集します。

リスト1 書き出され編集されたXAMLLコード(Mainpage.xaml)

(1)Page.Resorucesプロパティ要素内に、ListBoxTemplateというKey名でDataTemplate要素を配置する。その子要素としてStackPanel要素を配置し、背景色に「SlateBlue」、Marginに「10」を指定して余白を設ける。さらにその子要素としてTextBlock要素を配置し、Textプロパティに「zipcode」をバインドする。
再度StackPanel要素を配置し、Orientationプロパティに「Horizontal」を指定してオブジェクトのスタック方向を水平方向とする。その子要素としてTextBlock要素を3つ配置し、Textプロパティに上から順番に「prefecture」、「city」、「town」をバインドしておく。ここで指定した名前は、VBコード内のクラスで定義したプロパティ名だ。
(2)ViewBox要素を配置し、解像度に応じてオブジェクトのサイズが変更されるようにしておく。
(3)Grid要素の背景色を「Black」に指定する。
(4)「郵便番号検索」というタイトル用のTextBlock要素を配置する。
(5)「TextBox1」という名前で、住所を入力するTextBox要素を配置する。
(6)郵便番号の一覧を表示する、名前が「resultListBox」というListBox要素を配置する。ItemTemplateプロパティにStaticResourceを使って、(1)で定義したListBoxTemplateを参照する。
(7)AppbarButton要素を配置し、Iconプロパティに「Accept」、Labelプロパティに「OK」と指定する。このプロパティは図15の方法で設定できる。AppbarButtonを選択し、プロパティの[アイコン]ペインを展開して表示されるSymbolに「Accept」を選択し、[共通]ペイン内のLabelに「OK」と指定する。

図15:AppbarButton要素のプロパティを設定する(クリックで拡大)
<Page
  x:Class="App1_Common.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:App1_Common"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d">
  <Page.Resources>(1)
    <DataTemplate x:Key="ListBoxTemplate">(1)
      <StackPanel Background="SlateBlue" Margin="10">(1)
        <TextBlock Text="{Binding zipcode}" Foreground="Gold" FontSize="30"/>(1)
        <StackPanel Orientation="Horizontal" Width="1110" Margin="10">(1)
          <TextBlock Text="{Binding prefecture}" FontSize="24" Foreground="White"/>(1)
          <TextBlock Text="{Binding city}" FontSize="24" Foreground="White"/>(1)
          <TextBlock Text="{Binding town}" FontSize="24" Foreground="White"/>(1)
        </StackPanel>(1)
      </StackPanel>(1)
    </DataTemplate>(1)
  </Page.Resources>(1)
  <Viewbox>(2)
  <Grid Background="Black">(3)
    <Grid Height="639" Width="397">
      <TextBlock HorizontalAlignment="Left" Height="68" TextWrapping="Wrap" Text="郵便番号検索" VerticalAlignment="Top" Width="315" FontFamily="Meiryo UI" FontSize="50" Margin="52,0,0,0" Foreground="Crimson" FontWeight="Bold"/>(4)
      <TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="43" Margin="0,68,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="340"  FontFamily="Meiryo UI" FontSize="24"/>(5)
      <ListBox x:Name="ResultListBox" HorizontalAlignment="Right" Height="518" Margin="0,121,0,0" VerticalAlignment="Top" Width="397" ItemTemplate="{StaticResource ListBoxTemplate}" Background="White" BorderBrush="Black" FontFamily="Meiryo UI" FontSize="36" FontWeight="Bold"/>(6)
      <AppBarButton x:Name="okButton" HorizontalAlignment="Left" Height="73" Icon="Accept" Label="OK" Margin="323,56,0,0" VerticalAlignment="Top" Width="74" />(7)
    </Grid> 
  </Grid>(3)
  </Viewbox>(2)
</Page>

では早速プログラムコードを書いていきましょう。

コントロールの配置からも想像できるように、今回のプログラムはWeb APIを使って入力された住所の郵便番号を検索表示させるプログラムです。

入力された住所の郵便番号を表示

今回は、GROOVEの「郵便番号検索API」を使用します。詳細については下記のURLを参照してください。
参考:郵便番号検索API

プログラムコード (MainPage.xaml.vb)

名前空間の読み込み

HTTP 属性のクラスが含まれるSystem.Net.Http名前空間をインポートする。HttpClientクラスを使用するのに必要だ。
次に、コンテキストメニューおよび、メッセージダイアログをサポートするクラスの含まれる、Windows.UI.Popups名前空間をインポートする(リスト2)。

リスト2 (MainPage.xaml.vb)

Imports System.Net.Http
Imports Windows.UI.Popups

AddressInfoクラスの定義

AddressInfoクラス内で、文字列型の「zipcode(郵便番号)」、「prefecture(都道府県)」、「city(市)」、「town(町村)」プロパティを定義する(リスト3)。

リスト3

Public Class AddressInfo
  Property zipcode As String
  Property prefecture As String
  Property city As String
  Property town As String
End Class

okButton_Clickメソッドの処理

住所を入力するTextBox1に何も入力されない状態で[OK]ボタンがクリックされた時は、警告メッセージを表示して処理を抜ける。それ以外は以下の処理を行う。

「郵便番号検索API」のリクエストURIを変数myUriに格納し、引数wordに「TextBox1.Text」の値を指定する。引数formatには「xml」を指定して結果がXML形式で返されるよう指定する。

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

GetStringAsyncメソッドで、指定したURIにGET要求を送信し、非同期操作で応答本体を文字列として返し、その内容を変数resultXmlに格納しておく。
XElement.Parseメソッドで変数resultXmlの内容を文字列として読み込む。
AddressInfoクラスの新しいリストであるmyAddressInfoオブジェクトを作成する。
一度、myAddressInfoオブジェクトをクリアしておく。
Descendantsメソッドで全ての子孫要素「address」の内容を、変数resultに格納しながら以下の処理を繰り返す。

新しいAddressInfoクラスのzipcodeプロパティにzipcode要素の内容を「123-4567」という郵便番号形式で抜き出して指定する。結果XMLでは、通常はzipcod要素の値は「1234567」という形式になっているため、SubStringメソッドで指定した位置から、指定した文字数を取りだして「-(ハイフン)」で連結して指定している。
次にprefectureプロパティに「prefecture要素の値」を指定する。同様に、cityプロパティに「city要素の値」、townプロパティに「town要素の値」を指定して、AddメソッドでmyAddressInfoオブジェクトに追加している。
resultListBoxのItemsSourceプロパティにmyAddressInfoオブジェクトを指定する。
これで、入力した住所に該当する郵便番号が、住所とともに表示される。
非同期処理で行われるため、メソッドの先頭にAsyncを追加する。

具体的なコードはリスト4のようになる。

リスト4

Private Async Sub okButton_Click(sender As Object, e As RoutedEventArgs) Handles okButton.Click
  If TextBox1.Text = String.Empty Then
    Dim message As New MessageDialog("住所を入力してください。")
    Await message.ShowAsync
    Exit Sub
  Else
    Dim myUri As String = String.Format("http://api.postalcode.jp/v1/zipsearch?word={0}&format=xml", TextBox1.Text)
    Dim myHttpClient As New HttpClient
    Dim resultXml = Await myHttpClient.GetStringAsync(New Uri(myUri, UriKind.Absolute))
    Dim xmldoc As XElement = XElement.Parse(resultXml)
    Dim myAddressInfo As New List(Of AddressInfo)
    myAddressInfo.Clear()
    For Each result In From c In xmldoc.Descendants("address") Select c
      With myAddressInfo
        .Add(New AddressInfo With {
          .zipcode = result.Element("zipcode").Value.Substring(0, 3) & "-" & result.Element("zipcode").Value.Substring(3, 4),
          .prefecture = result.Element("prefecture").Value,
          .city = result.Element("city").Value,
          .town = result.Element("town").Value})
      End With
    Next
    ResultListBox.ItemsSource = myAddressInfo
  End If
End Sub

以上でプログラムは完成です。しかし、これだけではまだ動作はしません。

App.xaml.vbの編集

実際にプログラムを動かすには、まず「App1_Phone(Windows Phone 8.1)」プロジェクト内のApp.xaml.vbを開き、OnLaunchedイベント内の、リスト5の個所をリスト6のように書き直す必要があります。

リスト5 元のコード App.xaml.vb

If Not rootFrame.Navigate(GetType(MainPage), e.Arguments) Then
  Throw New Exception("Failed to create initial page")
End If

ナビゲーションのパラメーターとして、「MainPage」から「App1_Common.MainPage」に変更して指定します(リスト6)。

リスト6 編集されたコード App.xaml.vb(App_Windows Phone(Windows Phone 8.1))

If Not rootFrame.Navigate(GetType(App1_Common.MainPage), e.Arguments) Then
  Throw New Exception("Failed to create initial page")
End If

「App1_Windows(Windows 8.1)」プロジェクト内のApp.xaml.vbに対しても同じ編集をしておきます(リスト7)。

リスト7 編集されたApp.xaml.vb(App1_Windows(Windows 8.1))

If rootFrame.Content Is Nothing Then
  rootFrame.Navigate(GetType(App1_Common.MainPage), e.Arguments)
End If

これで、全ての設定は完了しました。まずソリューションエクスプローラー内で「App1_Phone(WindowsPhone 8.1)」を選択して、マウスの右クリックで表示されるメニューから、「スタートアッププロジェクトに設定」を選択すると「App1_Phone(Windows Phone 8.1)」の文字が太字に変わります。

ではこれで実行してみましょう(図16)。

図16:Windows Phone 8.1のエミュレータで実行した(クリックで拡大)

次に「Windows 8.1」を「スタートアッププロジェクトに設定」して実行してみましょう(図17)。

図17:Windows アプリで起動した(クリックで拡大)

通常なら画面の左隅上と右隅上にフレーム レートカウンターの数値が表示されますが、これは各App.xaml.vb内のEnableFrameRateCounterにFalseを指定すると消すことができます。デフォルトではTrueになっています(リスト8)。

リスト8  App.xaml.vb内のフレームレートカウンターの値をFalseに指定する

#If DEBUG Then
  ' デバッグ中にグラフィックスのプロファイル情報を表示します。
  If System.Diagnostics.Debugger.IsAttached Then
    ' 現在のフレーム レート カウンターを表示します
    Me.DebugSettings.EnableFrameRateCounter = False
  End If
#End If

以上がVisual Basicでユニバーサルアプリを作成する手順です。Visual Basicではユニバーサルアプリが作成できないと思っていたVisual Basicユーザーにとっては大変に嬉しいことです。是非Visual Basicユーザーの皆さんは、この記事を参考にVisual Basicでユニバーサルアプリに挑戦していただきたいと思います。

ちなみに、前回までの記事はC#を使った解説ですので、無料版、Visual Studio 2013 Express for Windowsでも作成が可能です。

  • Visual Basicで作るユニバーサルWindowsアプリ

    『ユニバーサルWindowsアプリ開発』 第6回のサンプルプログラムです。
薬師寺国安事務所

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

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