データ保存・bing検索・簡易縦書き機能の実装
プログラミングの前に
前回は、俳句・川柳アプリ「一日一句」の企画から設計・デザインまでの作業について解説しました。今回は、実装について解説します。少し長いですが、アプリの中で値を渡して処理している関係上、該当する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
「一日一句」プロジェクトファイル