「一日一句」完結編 〜リスト選択とソート表示の実装〜

2012年5月2日(水)
PROJECT KySS

表示ページの実装

入力ページで「一覧」ボタンをタップした時に表示される俳句のファイル・リストの中から年月が選択された時、この表示ページに移動させて、選択された年月の俳句を表示します。

この表示ページでは、今詠んだばかりの最新の俳句をすぐに確認できるように、「▼」ボタンで詠んだ順、「▲」ボタンで新しい順に並べ替える処理も実装します。

表示ページのデザイン(ShowHaiku.xaml)

ソリューションエクスプローラーのプロジェクト名を右クリックして表示される「追加/新しい項目」で、Portrait Pageを追加します。名前は、ShowHaiku.xamlとします。LayoutRootのGridのBackgroundには” #FFFFFFFA”を指定し、StackPanel部分をコメントアウトしておきます。

ツールボックスから、Image、Button、TextBlock、Rectangle、ListBoxコントロールをレイアウトします(図4)。

 図4:表示ページにコントロールをレイアウトする(クリックで拡大)

さらに、ListBoxの子要素としてItemTemplateを定義してStackPanelを配置し、その中に、日本語句と英語句、それらの作成年月日を表示する3個のTextBlock、区切り線として使うRectangleを配置します。

レイアウトした各コントロールのプロパティを調整し、完成したデザイン・コードは、リスト3になります。3個のTextBlockには、日本語句、英語句、俳句の作成年月日のデータをバインドできるようにします(下線部分)。

リスト3 表示ページのデザイン・コード(ShowHaiku.xaml)

<phone:PhoneApplicationPage 
  x:Class="DailyHaiku_in_Japanese.ShowHaiku"
  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"
  FontFamily="{StaticResource PhoneFontFamilyNormal}"
  FontSize="{StaticResource PhoneFontSizeNormal}"
  Foreground="{StaticResource PhoneForegroundBrush}"
  SupportedOrientations="Portrait" Orientation="Portrait"
  mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
  shell:SystemTray.IsVisible="True" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls" 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="15,0,15,0">
 
      <Image Height="60" HorizontalAlignment="Left" Margin="0,15,0,0" Name="HaikuLogo60px" Stretch="Fill" VerticalAlignment="Top" Width="60" Source="/DailyHaiku_in_Japanese;component/Image/HaikuLogo60px.png" />
 
      <!--年月表示-->
  <TextBlock Height="50" HorizontalAlignment="Left" Margin="130,22,0,0" Name="SelectedMonth" Text="" VerticalAlignment="Top" Width="250" Foreground="#FF00004B" FontSize="32" />
  
      <!--俳句表示-->
      <Button Height="60" HorizontalAlignment="Left" Margin="300,100,0,0" Name="SortAscendingButton" VerticalAlignment="Top" Width="60" Style="{StaticResource SortAscendingButtonStyle}" />
      <Button Height="60" HorizontalAlignment="Left" Margin="390,100,0,0" Name="SortDscendingButton" VerticalAlignment="Top" Width="60" Style="{StaticResource SortDescendingButtonStyle}" />
      <Rectangle Height="1" HorizontalAlignment="Left" Margin="0,160,0,15" Name="MyHaikuBorder" VerticalAlignment="Top" Width="450" Fill="#FF237A1E" />
      <ListBox Name="MyDailyHaikuListBox" Margin="0,175,0,15" FontSize="24">
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="vertical" Name="ShowDataPanel">
              <TextBlock Name="Haiku_ja_jpBlock" Text="{Binding 俳句日}"  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0,0,0,0" TextWrapping="Wrap" Foreground="#FF333333" FontSize="26" />
              <TextBlock Name="Haiku_enBlock" Text="{Binding 俳句英}"  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="48,5,0,0" TextWrapping="Wrap" Foreground="#FF237A1E" FontSize="24" />
              <TextBlock Name="Haiku_recordDateBlock" Text="{Binding 年月日}"  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0,5,0,0" Foreground="#FF64BA5E" FontSize="20" TextAlignment="Right" Width="450" />
              <Rectangle Height="1" HorizontalAlignment="Left" Margin="0,2,0,15" Name="DailyBorder" VerticalAlignment="Top" Width="450" Fill="#FF64BA5E" /> 
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
    </Grid> 
  </Grid>
</phone:PhoneApplicationPage>

このページでレイアウトしたButtonコントロールのスタイル設定については、リスト4 のコードをApp.xaml内の要素の子として追加します。

リスト4  App.xaml内に追加する、昇順・降順ボタンのスタイル設定(App.xaml)

    <Style x:Key="SortAscendingButtonStyle" TargetType="Button">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Grid>
              <Image x:Name="SortAscendingButtonImage" Source="/DailyHaiku_in_Japanese;component/Image/SortAscendingButton.png" Stretch="Fill"/>
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
 
    <Style x:Key="SortDescendingButtonStyle" TargetType="Button">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Grid>
              <Image x:Name="SortDescendingButtonImage" Source="/DailyHaiku_in_Japanese;component/Image/SortDescendingButton.png" Stretch="Fill"/>
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

表示ページのロジック(ShowHaiku.xaml.vb)

この表示ページでは、選択された年月のXMLファイルを読み込んで表示します。その構造は、リスト5のとおりです。

リスト5  表示する俳句のXMLドキュメント(年月.xml)の構造

<?xml version="1.0" encoding="utf-8"?>
<俳句集 年月="2012年1月">
    <俳句 創作年月日="2012年1月22日" 登録日時="2012/01/22/03:24:07">
      <句>
        改行された俳句 
      </句>
      <ルビ>ルビやコメントなど</ルビ>
      <英語句>
        改行された英語俳句 
      </英語句>
    </俳句>
  ~句の数だけ<俳句>要素、繰り返し~
</俳句集>

このXMLデータをソート表示する処理を記述していきます(リスト6)。

まず、ローカルストレージに保存されているファイルを処理するためにSystem.IO.IsolatedStorage名前空間を、XMLデータを処理するためにSystem.Xml.Linq名前空間をインポートしておきます。
俳句を詠んだ年月日、日本語句、英語句のデータを取得するためのクラスMyTitleDataを作成しておきます。

(1) 選択された年月データを受け取る処理

入力ページ(CreateHaiku.xaml.vb)のMyHaikuMonthListBox_SelectionChangedプロシジャからのパラメータを受け取る処理です。
選択された年月を受け取る変数を宣言し、ListBoxから選択された「年月」を変数ReadMonthに代入します。また、あらかじめソート処理対象のXML木を格納する変数ShowHaikuItemDoc を宣言しておきます。

(2) この表示ページがロードされた時の処理

この表示ページがロードされた時点では、俳句データを昇順表示するため、「昇順」ボタンは使用不可としておきます。
渡されてきた「年月」データに拡張子.xmlを付けて処理対象ファイルとします。選択されたファイルが存在する場合、XML木を読み込み、デフォルトの昇順ソート表示のSortAscendingプロシジャを実行します。

(3) デフォルトの昇順ソート表示の処理

このページの冒頭に記述しているMyTitleDataクラスを使い、新規リストを生成します。
俳句の登録順、すなわち文書順に「俳句」要素を指定して、その「創作年月日」属性値、子要素の「英語句」「句(日本語句)」の内容を取得します。
生成したリストに、各々取得したデータを追加して、ListBoxにデータを適用します。

(4) 降順ソート表示の処理

登録日時の逆順、すなわち逆文書順に「俳句」要素を取得して、そのデータをListBoxに適用して表示します。データの並び順以外は、昇順ソート表示の処理に同じです。

(5) 「昇順ソート」ボタンがタップされた時の処理

「昇順ソート」ボタンを使用不可とし、「降順ソート」ボタンを使用可として、昇順ソート表示の処理のSortAscendingプロシジャを実行します。

(6) 「降順ソート」ボタンがタップされた時の処理

「降順ソート」ボタンを使用不可とし、「昇順ソート」ボタンを使用可として、降順ソート表示の処理のSortDescendingプロシジャを実行します。

リスト6 表示ページのロジック・コード(ShowHaiku.xaml.vb)

Option Strict On
Imports System.IO.IsolatedStorage
Imports System.IO
Imports System.Xml.Linq

俳句データを取得するクラス

Public Class MyTitleData
  Property 年月日 As String
  Property 俳句日 As String
  Property 俳句英 As String
End Class

Partial Public Class ShowHaiku
  Inherits PhoneApplicationPage
 
  Public Sub New()
    InitializeComponent()
  End Sub

(1) CreateHaiku.xaml.vbのMyHaikuMonthListBox_SelectionChangedプロシジャからのパラメータを受け取る処理

  '●渡されるパラメータを受け取る変数を宣言
  Dim ReadMonth As String = String.Empty
 
  '●ListBoxから選択された「年月」を変数に代入
  Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
    Dim MonthParam As IDictionary(Of String, String) = NavigationContext.QueryString
    ReadMonth = MonthParam("Name")
    MyBase.OnNavigatedTo(e)
  End Sub
 
  '●ソート処理対象のXML木を格納する変数を宣言
  Dim ShowHaikuItemDoc As XDocument

(2) この表示ページがロードされた時の処理

  Private Sub ShowHaiku_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
    '●デフォルトは昇順表示なので、昇順ボタンを使用不可としておく
    SortAscendingButton.Opacity = 0.3
    SortAscendingButton.IsEnabled = False
 
    '●パラメータから渡された年月に拡張子.xmlを付けて処理対象ファイルとする
    Dim ShowHaikuStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
    Dim ShowHaikuFilePath As String = Path.Combine("DailyHaiku_in_Japanese_Data", ReadMonth & ".xml")
 
    '●タイトルを表示
    SelectedMonth.Text = ReadMonth & "の俳句"
 
    '●ListBoxから選択されたファイルが存在する場合の処理。ファイルのXML木を読み込み、昇順ソート表示を実行する
    If ShowHaikuStorage.FileExists(ShowHaikuFilePath) = True Then
      Dim ShowHaikuStream As IsolatedStorageFileStream = ShowHaikuStorage.OpenFile(ShowHaikuFilePath, FileMode.Open, FileAccess.Read)
      Dim ShowHaikuReader As StreamReader = New StreamReader(ShowHaikuStream, System.Text.Encoding.UTF8)
      Dim ShowHaikuReadXmldoc As String = ShowHaikuReader.ReadToEnd
      ShowHaikuItemDoc = XDocument.Parse(ShowHaikuReadXmldoc)
      ShowHaikuReader.Close()
      ShowHaikuStream.Close()
 
      SortAscending()
    
    Else
      Exit Sub
    End If
  End Sub

(3) デフォルトの昇順ソート表示の処理

  Private Sub SortAscending()
 
    '●このファイルの冒頭に記述しているMyTitleDataクラスを使い、新規リストを生成
    Dim MyKuList As New List(Of MyTitleData)
 
    '●登録順、すなわち文書順に「俳句」要素を取得
    Dim MyDataQuery As IEnumerable(Of XElement) = From c In ShowHaikuItemDoc.Descendants("俳句") Order By c.@登録日時 Ascending
 
    '●「俳句」要素の「創作年月日」属性値、子要素の「英語句」「句」の内容を取得
    For Each MyResult In MyDataQuery
 
      Dim MyRecordDate As String = MyResult.@創作年月日
      Dim MyKuEnglish As String = MyResult.Elements("英語句").Value
 
      '●英語句が未入力の場合、改行文字列が入っている可能性があるので、見た目を整えるため空にしておく
      If MyKuEnglish.Length > 0 Then
        MyKuEnglish = MyKuEnglish
      Else
        MyKuEnglish = String.Empty
      End If
 
      Dim MyData As String = MyResult.Elements("句").Value
 
      '●生成したリストに、各々取得したデータを追加
      MyKuList.Add(New MyTitleData With {.年月日 = MyRecordDate, .俳句日 = MyData, .俳句英 = MyKuEnglish})
    Next
    '●ListBoxにデータを適用
    MyDailyHaikuListBox.ItemsSource = MyKuList
  End Sub

(4) 降順ソート表示の処理

  Private Sub SortDescending()
    Dim MyKuList As New List(Of MyTitleData)
 
    '●登録日時の逆、すなわち逆文書順に「俳句」要素を取得。他の処理は昇順ソート表示に同じ
    Dim MyDataQuery As IEnumerable(Of XElement) = From c In ShowHaikuItemDoc.Descendants("俳句") Order By c.@登録日時 Descending
    For Each MyResult In MyDataQuery
 
      Dim MyRecordDate As String = MyResult.@創作年月日
      Dim MyKuEnglish As String = MyResult.Elements("英語句").Value
 
      If MyKuEnglish.Length > 0 Then
        MyKuEnglish = MyKuEnglish
      Else
        MyKuEnglish = String.Empty
      End If
 
      Dim MyData As String = MyResult.Elements("句").Value
        
      MyKuList.Add(New MyTitleData With {.年月日 = MyRecordDate, .俳句日 = MyData, .俳句英 = MyKuEnglish})
    Next
    MyDailyHaikuListBox.ItemsSource = MyKuList
  End Sub

(5)「昇順ソート」ボタンがタップされた時の処理

  Private Sub SortAscendingButton_Tap(sender As Object, e As System.Windows.Input.GestureEventArgs) Handles SortAscendingButton.Tap
 
    '●「昇順ソート」ボタンを使用不可とし、「降順ソート」ボタンを使用可とする
    SortAscendingButton.Opacity = 0.3
    SortAscendingButton.IsEnabled = False
 
    SortDscendingButton.Opacity = 1.0
    SortDscendingButton.IsEnabled = True
 
    '●昇順ソート表示の処理を実行
    SortAscending()
  End Sub

(6)「降順ソート」ボタンがタップされた時の処理

  Private Sub SortDscendingButton_Tap(sender As Object, e As System.Windows.Input.GestureEventArgs) Handles SortDscendingButton.Tap
 
    '●「降順ソート」ボタンを使用不可とし、「昇順ソート」ボタンを使用可とする
    SortDscendingButton.Opacity = 0.3
    SortDscendingButton.IsEnabled = False
 
    SortAscendingButton.Opacity = 1.0
    SortAscendingButton.IsEnabled = True
 
    '●降順ソート表示の処理を実行
    SortDescending()
  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メルマガ会員のサービス内容を見る

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