ロジックコードを記述する
次に、DataIchiranPage.xamlを展開して表示される、DataIchiranPage.xaml.vbをダブルクリックしてリスト4のコードを記述します。
ロジックコードを記述する
リスト4 (DataIchiranPage.xaml.vb)
Option Strict On
Imports System.Xml.Linq
Imports System.IO
Imports System.IO.IsolatedStorage
Imports System.Windows.Media.Imaging
Imports Microsoft.Phone
ImageInfoクラス内に、WriteableBitmapクラス型のimageFileNameと、文字列型のrecordDateプロパティを定義しておきます。
Public Class ImageInfo
Property imageFileName As WriteableBitmap
Property recordDate As String
End Class
Partial Public Class DataIchiranPage
Inherits PhoneApplicationPage
Public Sub New()
InitializeComponent()
End Sub
新しいMenuItemクラスのインスタンスmyMenuItem1~myMenuItem2をメンバ変数として宣言します。MenuItemクラスは、ContextMenu 内に表示される個別の項目を表すクラスです。
Dim myMenuItem1 As New MenuItem
Dim myMenuItem2 As New MenuItem
ContextMenuクラスの新しいインスタンスmyContextMenuオブジェクトをメンバ変数として宣言します。ContextMenuコントロールは、コントロールのコンテキストに固有の機能を公開するポップアップメニューを表示するコントロールです。このコントロールは、Silverlight for Windows Phone Toolkit - Nov 2011.msiに含まれていますので、下記URLよりダウンロードしてインストールしてください。
→参照:Windows Phone Toolkit - Nov 2011 (7.1 SDK)
Dim myContextMenu As New ContextMenu
Dim imageName As String
Dim doc As XElement
Dim myIndex As Integer
ページがアクティブになった時の処理
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。Path.CombineメソッドでImageInFrameフォルダとImageList.xmlのファイル名を連結して、filePath変数に格納します。
IsolatedStorageFileクラスのOpenFileメソッドで、ImageInFrameフォルダ内のImageList.xmlファイルを、指定したファイルアクセスを使用して指定したモードで開き、StreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り、変数readXmldocに格納しておきます。読み込んだXMLテキストをParseメソッドでXElementとして読み込みます。
ImageInfoクラスの新しいリストであるmyImageInfoを作成します。
Descendantsメソッドで、子孫要素であるすべての 要素のコレクションを選択し、各要素を、変数resultに格納しながら、以下の処理を繰り返します。
Path.Combineメソッドで、ImageInFrameフォルダと要素の内容を連結して、変数imageFilePathに格納しておきます。
変数imageStorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数stream変数を用意し、IsolatedStorageFile.OpenFileメソッドでimageFilePathに格納しているファイルを、指定したモード、指定したファイルアクセスモードで開きます。
WriteableBitmap型の変数imageSourceを宣言し、PictureDecoder.DecodeJpegメソッドで、開いたストリームをJPEGファイルとしてWriteableBitmapオブジェクトにデコードします。PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。
ImageInfoクラスのimageFileNameプロパティに、読み込んだWriteableBitmapオブジェクトのimageSourceオブジェクトを指定し、recordDateプロパティに要素の属性”記録日”の値を指定して、AddメソッドでmyImageInfoオブジェクトに追加していきます。ListBox1のItemsSourceプロパティにmyImageInfoオブジェクトを指定します。
これで、撮った画像と記録日の一覧が表示されます。
Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
Dim filePath As String = Path.Combine("ImageInFrame", "ImageList.xml")
Using myStream As IsolatedStorageFileStream = storage.OpenFile(filePath, FileMode.Open, FileAccess.Read)
Using reader As StreamReader = New StreamReader(myStream)
Dim readXmldoc As String = reader.ReadToEnd
doc = XElement.Parse(readXmldoc)
Dim myImageInfo As New List(Of ImageInfo)
For Each result In From c In doc.Descendants("風景") Select c
Dim imageFilePath As String = Path.Combine("ImageInFrame", result.Element("画像名").Value)
Dim imageStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
Using stream As IsolatedStorageFileStream = imageStorage.OpenFile(imageFilePath, FileMode.Open, FileAccess.Read)
Dim imageSource As WriteableBitmap = PictureDecoder.DecodeJpeg(stream)
With myImageInfo
.Add(New ImageInfo With {.imageFileName = imageSource,
.recordDate = result.Attribute("記録日").Value})
End With
'stream.Close()
End Using
Next
ListBox1.ItemsSource = myImageInfo
End Using
End Using
MyBase.OnNavigatedTo(e)
End Sub
リストボックスから任意の画像が選択された時の処理
ListBoxより、選択されたインデックスをメンバ変数myIndexに格納しておきます。
myIndexに該当する要素の子要素の値を取得して、メンバ変数imageNameに格納しておきます。MenuItem型の新しいリストであるmenuItemListを作成します。
Header、FontSize、FontWeightプロパティを設定し、memuItemListオブジェクトに各プロパティの設定されたmenuItem1とmenuItem2を追加します。ContextMenuのItemsSourceにmenuItemListオブジェクトを指定し、透明度を表すOpacityに0.8を指定して、少し透明化させます。ContextMenuService.SetContextMenu メソッドでListBoxオブジェクトにmyContextMenuオブジェクトの値を設定します。IsOpenメソッドでコンテキストメニューを開きます。
AddHandlerステートメントでmyMenuItem1とmyMenuItem2のClickイベントにmyMenuItem_Clickのイベントハンドラを指定します。その前に、一度RemoveHandlerステートメントで削除のイベントである、myMenuItem1のClickイベントのイベントハンドラを削除しておきます。この処理を追加していないと、削除確認のメッセージが重複して表示される場合があります。
Private Sub ListBox1_SelectionChanged(sender As Object, e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
Try
myIndex = ListBox1.SelectedIndex
imageName = doc.Descendants("風景")(myIndex).Element("画像名").Value
Dim menuItemList As New List(Of MenuItem)
myMenuItem1.Header = "データの削除"
myMenuItem1.FontSize = 25
myMenuItem1.FontWeight = FontWeights.Bold
myMenuItem2.Header = "キャンセル"
myMenuItem2.Foreground = New SolidColorBrush(Colors.Red)
myMenuItem2.FontSize = 25
myMenuItem2.FontWeight = FontWeights.Bold
menuItemList.Add(myMenuItem1)
menuItemList.Add(myMenuItem2)
myContextMenu.ItemsSource = menuItemList
myContextMenu.Opacity = 0.8
ContextMenuService.SetContextMenu(ListBox1, myContextMenu)
myContextMenu.UpdateLayout()
myContextMenu.IsOpen = True
RemoveHandler myMenuItem1.Click, AddressOf myMenuItem_Click
AddHandler myMenuItem1.Click, AddressOf myMenuItem_Click
AddHandler myMenuItem2.Click, AddressOf myMenuItem_Click
Catch
Exit Sub
End Try
End Sub
ContextMenuに表示されたメニューがタップされた時の処理
senderオブジェクトからMenuItemのHeaderプロパティの情報を取得して、変数selectHeaderに格納しておきます。selectHeaderの値で条件分岐を行います。
値が「データの削除」の場合は、削除確認メッセージを表示し、[ok]の場合は、DeleteDataプロシージャを実行します。[キャンセル]の場合は、ContexMenuを閉じ、ListBoxの選択を解除します。
Private Sub myMenuItem_Click(sender As Object, e As EventArgs)
Try
Dim selectHeader = DirectCast(sender, MenuItem).Header
Select Case selectHeader.ToString
Case "データの削除"
Dim kakunin = MessageBox.Show("このデータを削除しますか?", "削除確認", MessageBoxButton.OKCancel)
Select Case kakunin
Case MessageBoxResult.OK
DeleteData()
Exit Select
Case Else
ListBox1.SelectedIndex = -1
Exit Sub
End Select
Case "キャンセル"
myContextMenu.IsOpen = False
ListBox1.SelectedIndex = -1
Exit Select
Case Else
ListBox1.SelectedIndex = -1
Exit Select
End Select
Catch
Exit Sub
End Try
End Sub
データを削除する処理
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。分離ストレージ内のImageInFrameフォルダとImageList.xmlというファイルをPath.Combineメソッドで連結し、変数filePathに格納しておきます。ImageInFrameフォルダ内にImageList.xmlファイルが存在していた場合は、分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStreamを用意し、IsolatedStorageFile.OpenFileメソッドでfilePathに格納しているファイルを、指定したモード、指定したファイルアクセスモードで開きます。開いたファイルをStreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り変数readXmldocに格納しておきます。
読み込んだXMLテキストを、ParseメソッドでXElementとして読み込みます。myStreamオブジェクトを閉じます。
読み込んだXMLから、メンバ変数myIndexに該当する要素の子要素の値を取得し、変数delImageに格納しておきます。分離ストレージ内のImageInFrameフォルダにある、delImageに格納されている画像ファイル名をPath.Combineメソッドで連結して、変数delJPGfileに格納します。DeleteFileメソッドで、このファイルを削除します。
メンバ変数myIndexに該当する要素を選択します。Removeメソッドで、この要素とその子要素を全て削除します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数streamを用意し、filePath変数と、ファイルモード(作成モード)、ファイルアクセス(書き込み)で初期化された、新しいIsolatedStorageFileStreamを作成します。Saveメソッドで要素とその子要素の削除されたXMLを保存します。削除した旨を表示します。
要素を選択するクエリを定義します。要素が存在しない (全てのデータが削除された)場合は、ImageList.xml自体を削除し、MainPage.xamlに遷移します。まだImageList.xmlが存在している場合は、DataIchiranPage.xamlに遷移し、削除されたListBoxを再描画します。
Sub DeleteData()
Dim delXml As XElement
Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
Dim filePath As String = Path.Combine("ImageInFrame", "ImageList.xml")
If storage.FileExists(filePath) = True Then
Dim myStream As IsolatedStorageFileStream = storage.OpenFile(filePath, FileMode.Open, FileAccess.Read)
Using reader As StreamReader = New StreamReader(myStream, System.Text.Encoding.UTF8)
Dim readXmldoc As String = reader.ReadToEnd
delXml = XElement.Parse(readXmldoc)
myStream.Close()
End Using
Dim delImage As String = delXml.Descendants("風景")(myIndex).Element("画像名").Value
Dim delJPGfile As String = Path.Combine("ImageInFrame", delImage)
If delImage <> String.Empty Then
storage.DeleteFile(delJPGfile)
End If
Dim delElement = delXml.Descendants("風景")(myIndex)
delElement.Remove()
Using stream As IsolatedStorageFileStream = New IsolatedStorageFileStream(filePath, FileMode.Create, FileAccess.Write, storage)
delXml.Save(stream)
End Using
MessageBox.Show("データを削除しました。")
Dim allDeleteQuery = From c In delXml.Descendants("風景") Select c
If allDeleteQuery.Count <= 0 Then
storage.DeleteFile(filePath)
storage.Dispose()
NavigationService.Navigate(New Uri(String.Format("/MainPage.xaml?date={0}", DateTime.Now.ToShortDateString & DateTime.Now.ToLongTimeString), UriKind.Relative))
Exit Sub
End If
storage.Dispose()
NavigationService.Navigate(New Uri(String.Format("/DataIchiranPage.xaml?date={0}", DateTime.Now.ToShortDateString & DateTime.Now.ToLongTimeString), UriKind.Relative))
Else
storage.Dispose()
Exit Sub
End If
End Sub
Backボタン(←)がタップされた時の処理
NavigationService.BackStack.Countで画面遷移の履歴スタック数を取得し、変数myStacCountに格納しておきます。
myStacCount -2と記述し、NavigationService.RemoveBackEntry()で、MainPageのみを残して遷移スタックを削除します。myStacCount -1とすると、アプリケーションが終了してしまうので注意してください。
Protected Overrides Sub OnBackKeyPress(e As System.ComponentModel.CancelEventArgs)
Dim myStacCount = NavigationService.BackStack.Count
For i As Integer = 0 To myStacCount - 2
NavigationService.RemoveBackEntry()
Next
MyBase.OnBackKeyPress(e)
End Sub
End Class
今回のサンプルは以上で終了です。
【参照リンク】
PROJECT KySSでは現在、16個のWindows PhoneアプリをMarketplaceに公開しています。試用版もありますので、興味のある方はお試しください。
→参照:Windows Phone App Information(PROJECT KySS)
- この記事のキーワード