データ保存・bing検索・簡易縦書き機能の実装

2012年4月10日(火)
PROJECT KySS

プログラミングの前に

前回は、俳句・川柳アプリ「一日一句」の企画から設計・デザインまでの作業について解説しました。今回は、実装について解説します。少し長いですが、アプリの中で値を渡して処理している関係上、該当する3つのページのコードを一気に解説しますので、気長にお付き合いください。

サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。

また、このアプリはマーケットプレイスで無料公開されています。
→参照:DailyHaiku(Windows Phone Marketplace)

Windows Phone アプリの開発フレームワークには、XNA Frameworkと Silverlightがあります。XNAはリアルタイムゲーム向けで、SilverlightはRIA向けです。「一日一句」は、Silverlightアプリケーションで、開発言語はVisual Basicです。

本連載では、以前の連載の読者を対象に、実開発からマーケットプレイスへの公開までを解説しています。これからWindows Phone アプリ開発を始める場合は、過去記事「Windows Phone 開発環境の構築と最初のプログラム」を参考に、開発環境を整備してください。

その際、Windows Phone SDK 7.1.1 Update
が発表されていますので、これもインストールしてください。日本語版をインストールする場合は、「Change Language」で Japanese に変更できます。記事中で紹介するアプリは、Windows Phone SDK 7.1の環境で開発しましたが、7.1.1でも問題なく動作します。

なお、筆者の開発環境は、Windows 7 Professional (32 bit) SP1、Visual Studio 2010 Ultimate SP1 (英語版)、Windows Phone SDK 7.1.1 (英語版)、Expression Studio 4(英語版)、Windows Phone Emulator、実機(Windows Phone IS12T)です。画面キャプチャのメニューは英語ですが、日本語版も手順は同じです。

アプリの機能と画面遷移

このアプリの画面遷移

前回記事で述べたとおり、このアプリは4つのページで構成します(図1)。メインページと入力ページはPortrait Page、一画面に内容が収まりそうにない表示ページとヘルプページはPanorama Pageです。

それぞれのページの名前は、図1中の青文字のとおりです。

図1:このアプリのページ構成と画面遷移(クリックで拡大)

各ページに実装する機能

メインページ(季節の選択、ヘルプページへのリンク)
  • 「春」「夏」「秋」「冬」の画像ボタンを配置し、季節を選択できるようにします。季節と月の対応は、おおむね、春(3月、4月、5月)、夏(6月、7月、8月)、秋(9月、10月、11月)、冬(12月、1月、2月)ですが、諸説あります。また、夏に冬の俳句を詠みたい場合や、8月31日23時59分に秋の句を詠むケースも考えられるため、ユーザーが自由に選択できるようにします。
  • 「?」ボタンを置き、ヘルプページにリンクします。
入力ページ(データの入力・検証・保存、季語のbing検索)
  • 俳句と、ルビやコメントを入力できるようにします。
  • 児童の利用を考え、ひらがなのみの字あまり最大19文字まで入力可能とします。
  • 入力文字列は簡易縦書きで表示します。
  • 必須項目と全角半角を検証し、不備がある場合はメッセージを表示します。
  • 「保存」ボタンがタップされた時、年月日、俳句、あればルビの記録された季節別のファイルを、実機内の DailyHaikuData フォルダに保存します。このバージョンは国内向けであり、季語が意味を持つことから、俳句データは季節別のファイルに分けます。データ形式は、投稿のための選定や、句集の編集などに利用できるよう、再利用の容易なXMLです。
  • 「季語検索」ボタンがタップされた時、選択されている季節の季語を、bingで検索させます。
  • 「季節選択」ボタンがタップされた時、メインページに戻って季節を再選択できるようにします。
  • 「一覧」ボタンがタップされた時は、現在選択されている季節の値を表示ページに渡して移動します。
表示ページ(俳句の簡易縦書き表示)
  • 選択されている季節の俳句が1句以上記録されている場合、俳句データを、簡易縦書きで巻物のように画面の右端から表示します(図2)。多数の俳句が記録されている場合でも、左フリックにより最後に保存された最新の句が表示されるため、確認が容易になります。
  • 「一句前へ」ボタンで一句ずつ巻き戻し、「一句目へ」ボタンで先頭の句にジャンプ、「一句後へ」ボタンで一句ずつ早送りします。
  • 「季節選択」ボタンがタップされた時は、メインページに戻って季節を再選択できるようにします。

図2:季節の俳句データを簡易縦書きで巻物のように表示する(クリックで拡大)
ヘルプページ(ヘルプ、ファイルの削除)
  • アプリの説明と操作手順を記載します。
  • 各季節別の記録済み俳句ファイルを削除できるようにします。誤って削除することのないよう、この削除機能はヘルプの最終ページに置きます。

値の渡し方

メインページで選択した季節の値は、入力ページに渡して季語検索と保存処理に利用し、さらに表示ページに渡して、表示するために読み込むXML文書の特定に用います。

例えば「春」を選択した場合、入力ページでは春の季語を検索し、入力した俳句はspring.xmlに保存します。さらに表示ページに移動した時は、spring.xmlのデータを表示するといった具合です。

これらの処理は、図3のように値を受け渡すことで実現しています。

図3:メインページで選択した「季節」データの渡し方(クリックで拡大)

メインページ(季節選択、ヘルプへのリンク)の実装

新規プロジェクトの作成

では、早速開発していきましょう。

「ファイル/ File 」「新規/ New 」「プロジェクト/ Project…」を選択し、開発言語として「Visual Basic」を選択、「Silverlight for Windows Phone」「Windows Phone Application」を選択します。

プロジェクト名は、「DailyHaiku」 としておきます(図4)。

「Windows Phone 7.1」環境の場合は、「Windows Phone 7.0」か、「Windows Phone 7.1」かを選択します。このアプリは 7.1 で作成しています。

図4:「DailyHaiku」プロジェクトを作成する(クリックで拡大)

プロジェクト名を右クリックして表示されるメニューから「追加/新規フォルダ」を選択してフォルダを追加し、名前を「Image」としておきます。このImageフォルダを右クリックして表示されるメニューから「追加/既存のアイテム」を選択して、画像部品一式を追加しておきます(図5)。

※画像ファイルは、ダウンロードできるプロジェクトの中に追加済みです。

図5:Imageフォルダを作成し、アプリ内で使う画像を追加しておく(クリックで拡大)

メインページのデザイン(MainPage.xaml)

まず、背景色を設定しておきます。名前がLayoutRootのGridのBackgroundに“#FFFFFFFA”を指定します。PC用のマルチタッチディスプレイでは淡いベージュに見えるこの色も、実機では一見白にしか見えませんが、白と比べるとまぶしすぎず、落ち着いた感じになります。

今回StackPanelは使わないので、その部分のコードはコメントアウトしておきます(図6)。

図6:StackPanel部分のコードはコメントアウトしておく(クリックで拡大)

次に、ツールボックスからImageコントロールを7個、ドラッグして配置します(図7)。

7個のImageコントロールに名前を付け(図8)、Sourceには、それぞれロゴのタイル、「春」「夏」「秋」「冬」の4つのボタン、「ヘルプ」ボタン、開発者のロゴの画像を指定します(図9)。

図7:ツールボックスから7個のImageコントロールを配置する(クリックで拡大)

図8:Imageコントロールに名前を付ける(クリックで拡大)

図9:それぞれのImageコントロールのプロパティを開き、Sourceに画像を指定する(クリックで拡大)

全てのコントロールのマージンを調整し、完成したデザイン・コードは、リスト1になります。

リスト1 メインページのデザイン・コード(MainPage.xaml)

<phone:PhoneApplicationPage 
  x:Class="DailyHaiku.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
  FontFamily="{StaticResource PhoneFontFamilyNormal}"
  FontSize="{StaticResource PhoneFontSizeNormal}"
  Foreground="{StaticResource PhoneForegroundBrush}"
  SupportedOrientations="Portrait" Orientation="Portrait"
  shell:SystemTray.IsVisible="True" Language="ja-JP">
  
  <!--LayoutRoot is the root grid where all page content is placed-->
  <Grid x:Name="LayoutRoot" Background="#FFFFFFFA">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
 
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
      <Image Height="140" HorizontalAlignment="Left" Margin="155,50,0,0" Name="logoIcon" Stretch="Fill" VerticalAlignment="Top" Width="140" Source="/DailyHaiku;component/Image/dailyHaiku_logo.png" />
      <Image Height="60" HorizontalAlignment="Left" Margin="332,130,0,0" Name="helpIcon" Stretch="Fill" VerticalAlignment="Top" Width="60" Source="/DailyHaiku;component/Image/dailyHaiku_help.png" />
  
      <Image Height="160" HorizontalAlignment="Left" Margin="232,230,0,0" Name="springButton" Stretch="Fill" VerticalAlignment="Top" Width="160" Source="/DailyHaiku;component/Image/dailyHaiku_spring.png" />
      <Image Height="160" HorizontalAlignment="Left" Margin="232,400,0,0" Name="summerButton" Stretch="Fill" VerticalAlignment="Top" Width="160" Source="/DailyHaiku;component/Image/dailyHaiku_summer.png" />
      <Image Height="160" HorizontalAlignment="Left" Margin="62,230,0,0" Name="autumunButton" Stretch="Fill" VerticalAlignment="Top" Width="160" Source="/DailyHaiku;component/Image/dailyHaiku_autumn.png" /> 
      <Image Height="160" HorizontalAlignment="Left" Margin="62,400,0,0" Name="winterButton" Stretch="Fill" VerticalAlignment="Top" Width="160" Source="/DailyHaiku;component/Image/dailyHaiku_winter.png" />
  
      <Image Height="50" HorizontalAlignment="Left" Margin="176,660,0,0" Name="developerLogo" Stretch="Fill" VerticalAlignment="Top" Width="101" Source="/DailyHaiku;component/Image/dailyHaiku_SSDlogo.png" />
  
    </Grid>
  </Grid>
</phone:PhoneApplicationPage>

メインページのロジック(MainPage xaml.vb)

レイアウトができたら、ソリューションエクスプローラー中のMainPage.xamlを展開して表示されるMainPage.xaml.vbの中に、処理を記述していきます。

まず、季節を代入する変数selectSeasonNameを宣言しておきます。

「春」ボタンがタップされた時、変数selectSeasonNameに「spring」という文字列を代入し、inputHaikuプロシジャを実行します。「夏」ボタンがタップされた時は「summer]、「秋」ボタンでは「autumn」、「冬」ボタンでは「winter」をそれぞれ変数selectSeasonNameに代入して、inputHaikuプロシジャを実行します。

inputHaikuプロシジャでは、変数selectSeasonNameに代入されている季節名を、入力ページ(createHaiku)に渡します。この値は、季語検索や保存するファイル名として利用するようになります。

入力ページおよび表示ページから「homeに戻った」という情報が渡された時には、RemoveBackEntryで履歴を除去します(前回記事も参照)。これにより、メインページを表示する前に表示していた他のページがあった場合、実機の「戻る」ボタンを押しても以前のページには戻らず、アプリケーションは終了します。

リスト2 メインページのロジック・コード(MainPage.xaml.vb)

Option Strict On

Partial Public Class MainPage
  Inherits PhoneApplicationPage

  ' Constructor
  Public Sub New()
    InitializeComponent()
  End Sub

  Dim selectSeasonName As String = String.Empty
 
  Private Sub springButton_Tap(sender As System.Object, e As System.Windows.Input.GestureEventArgs) Handles springButton.Tap
    selectSeasonName = "spring"
    inputHaiku()
  End Sub
 
  Private Sub summerButton_Tap(sender As System.Object, e As System.Windows.Input.GestureEventArgs) Handles summerButton.Tap
    selectSeasonName = "summer"
    inputHaiku()
  End Sub
 
  Private Sub autumunButton_Tap(sender As System.Object, e As System.Windows.Input.GestureEventArgs) Handles autumunButton.Tap
    selectSeasonName = "autumn"
    inputHaiku()
  End Sub
 
  Private Sub winterButton_Tap(sender As System.Object, e As System.Windows.Input.GestureEventArgs) Handles winterButton.Tap
    selectSeasonName = "winter"
    inputHaiku()
  End Sub
 
  Private Sub inputHaiku()
    NavigationService.Navigate(New Uri("/createHaiku.xaml?Name=" & selectSeasonName, UriKind.Relative))
    End Sub
 
  Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
    Dim no As Integer = NavigationService.BackStack.Count
    Dim home As String = String.Empty
 
    If NavigationContext.QueryString.TryGetValue("home", CStr(True)) Then
      For i = 0 To no
        NavigationService.RemoveBackEntry()
        MyBase.OnNavigatedTo(e)
      Next
    End If
  End Sub
 
  Private Sub helpIcon_Tap(sender As System.Object, e As System.Windows.Input.GestureEventArgs) Handles helpIcon.Tap
    NavigationService.Navigate(New Uri("/DailyHaikuHelp.xaml", UriKind.Relative))
  End Sub
End Class
  • 「一日一句」プロジェクトファイル

四国のSOHO。薬師寺国安(VBプログラマ)と、薬師寺聖(デザイナ、エンジニア)によるコラボレーション・ユニット。1997年6月、Dynamic HTMLとDirectAnimationの普及を目的として結成。共同開発やユニット名義での執筆活動を行う。XMLおよび.NETに関する著書や連載多数。最新刊は「Silverlight実践プログラミング」両名とも、Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。http://www.PROJECTKySS.NET/

連載バックナンバー

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

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

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

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