お気に入りの写真に登場する、仲良しクラウディアちゃん

2013年6月11日(火)
薬師寺 国安

ピクチャライブラリへのアクセス許可

ピクチャライブラリに内に、ClaudiaData2というフォルダを作成して、現在の年月日時分秒.xmlを保存します。そのため、ピクチャライブラリへのアクセス権が必要になります。
ソリューションエクスプローラー内のPackage.appxmanifestをダブルクリックして開きます。
「機能」タブ内の「画像ライブラリ」にチェックを付けてください。

Windows ストア空白のページの作成(DataShowPage.xaml)

VS2012のメニューの「プロジェクト(P)/新しい項目の追加(W)」と選択して、左に表示される項目からWindows ストアを選択します。
右に表示されるテンプレートから「空白のページ」を選択します。「名前(N):」にはDataShowPage.xamlと指定して、[追加(A)]ボタンをクリックします。

コントロールの配置

ツールボックスからDataShowPage.xamlのデザイン画面上にコントロールを配置します。Canvasコントロールを1個、MediaElementコントロールを1個、Buttonコントロールを1個、次にTextBlockコントロールを1個、次にButtonコントロールを1個、最後にTextBlockコントロールを1個配置しています。

書き出されるXAMLコードはリスト3、レイアウトは図8のようになります。

リスト3 書き出されたXAMLコード(DataShowPage.xaml)

  • (1) 名前がShowAreaという要素を配置しています。
  • (2) 名前がMediaElement1という要素を配置しています。
  • (3) 名前がplayButtonという
  • (4) タイトルを表示する要素を配置しています。文字色にPinkを指定しています。
  • (5) 名前がdelButtonという
  • (6) 名前がdelTextBlockという要素を配置し、Textプロパティに「削除しました!」と指定しておきます。文字色にはRedを指定し、最初の状態ではVisibilityにCollapsedを指定して非表示としておきます。
01<Page
02  x:Class="WithClaudia2.DataShowPage"
05  xmlns:local="using:WithClaudia2"
08  mc:Ignorable="d">
09  <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
10    <Canvas x:Name="ShowArea" HorizontalAlignment="Left" Height="480" Margin="303,167,0,0" VerticalAlignment="Top" Width="640"/>■(1)
11    <MediaElement x:Name="MediaElement1" HorizontalAlignment="Left" Height="58" Margin="1010,394,0,0" VerticalAlignment="Top" Width="280"/>■(2)
12    <Button x:Name="playButton" HorizontalAlignment="Left" Height="92" Margin="487,666,0,0" VerticalAlignment="Top" Width="129" Style="{StaticResource PlayAppBarButtonStyle}"/>■(3)
13    <TextBlock HorizontalAlignment="Left" Height="107" Margin="246,31,0,0" TextWrapping="Wrap" Text="仲良しクラウディアちゃん!" VerticalAlignment="Top" Width="818" FontFamily="Meiryo UI" FontSize="72" FontWeight="Bold" Foreground="Pink"/>■(4)
14    <Button x:Name="delButton" HorizontalAlignment="Left" Height="92" Margin="621,666,0,0" VerticalAlignment="Top" Width="97" Style="{StaticResource DeleteAppBarButtonStyle}"/>■(5)
15    <TextBlock x:Name="delTextBlock" HorizontalAlignment="Left" Height="125" Margin="246,310,0,0" TextWrapping="Wrap" Text="削除しました!" VerticalAlignment="Top" Width="730" FontFamily="Meiryo UI" FontSize="100" FontWeight="Bold" Foreground="Red" Visibility="Collapsed"/>■(6)
16  </Grid>
17</Page>
図8:各種コントロールを配置した(クリックで拡大)

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト4のコードを記述します。

ロジックコードを記述する

リスト4 (MainWindow.xaml.vb)

ファイルの閲覧、開くファイルの選択、名前、拡張子、ファイルの格納場所の選択を行うことのできる機能を提供するクラスの含まれる、Windows.Storage.Pickers名前空間をインポートします。

1Imports Windows.Storage.Pickers

シーケンシャルアクセスストリームおよびランダムアクセスストリームに対する、読み込みと書き込みのサポートを提供するクラスの含まれる、Windows.Storage.Streams名前空間をインポートします。

1Imports Windows.Storage.Streams

ファイルやフォルダおよびアプリケーションの設定を管理するクラスの含まれる、Windows.Storage名前空間をインポートしす。

1Imports Windows.Storage

ClaudiaInfoクラス内に文字列型のClaudiaImageプロパティを定義しています。

1Public Class ClaudiaInfo
2  Property ClaudiaImage As String
3End Class
4 
5Public NotInheritable Class MainPage
6  Inherits Page

ファイルを表すStorageFileクラス型のメンバ変数claudiaImageを宣言します。

1Dim claudiaImage As StorageFile

Imageクラス型のメンバ変数myClaudiaImageを宣言します。

1Dim myClaudiaImage As Image

オブジェクトに複数の変換操作を適用するCompositeTransformクラス型のメンバ変数、myTransを宣言します。

1Dim myTrans As CompositeTransform
2 
3Dim myFileName As String

XMLの要素を表すXElementクラス用メンバ変数xmldocを宣言します。

1Dim xmldoc As XElement
2 
3Dim claudiaImageFileName As String

ファイルを表すStorageFileクラスのメンバ変数myPersonalImageを宣言します。

1Dim myPeronalImage As StorageFile
2 
3Dim SoundFile As String

XMLの要素を表すXElementクラスのメンバ変数soundXmlを宣言します。

1Dim soundXml As XElement
2 
3Dim mySelectedFile As String

ページがアクティブになった時の処理

ピクチャライブラリのClaudiaData2フォルダ内にファイルが存在した場合は、リストボックスにファイルの一覧を表示し、クラウディアの画像と、音声用のファイルを表示するDataShowプロシージャを実行します。

1Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
2  DataShow()
3  MyBase.OnNavigatedTo(e)
4End Sub

ピクチャライブラリのClaudiaData2フォルダ内にファイルが存在した場合は、リストボックスにファイルの一覧を表示し、クラウディアの画像と、音声用のファイルを表示する処理

ピクチャライブラリにアクセスします。
CreateFolderAsyncメソッドでピクチャライブラリ内にClaudiaData2というサブフォルダを作成します。
CreationCollisionOption.OpenIfExistsと指定すると、同名フォルダがある場合は、そのフォルダ名を返し、ない場合は新規に作成します。
GetFilesAsyncメソッドでClaudiaData2フォルダ内のファイルを取得しコレクション変数myFileに格納します。
Countプロパティでファイルの個数を取得し、ファイルが存在する場合は、以下の処理を行います。

文字列型の新しいリストであるmyXmlListオブジェクトを作成します。
コレクション変数myFile内を変数fileResultで反復処理しながら、以下の処理を行います。
myXmlListオブジェクトのAddメソッドでXMLファイルをmyXmlListオブジェクトに追加していきます。
fileResult.Pathでは絶対パス付きのファイル名が返されますので、Path.GetFileNameWithoutExtensionメソッドで、パスと拡張子を除いたファイル名を取得し、再度”.xml”という拡張子を追加しています。
fileListBoxのItemsSourceプロパティにmyXmlListオブジェクトを指定します。
これでClaudiaData2フォルダ内にXMLファイルが存在すれば、リストボックスに表示されます。

XElement.LoadメソッドでXMLファイル文書(Claudia.xml)を読み込みます。
ClaudiaInfoクラス型の新しいリストである、myClaudiaInfoオブジェクトを作成します。
Descendantsメソッドですべての子孫要素コレクションに対して変数resultに要素の内容を格納しながら、ClaudiaInfoクラスのClaudiaImageプロパティに、Imagesフォルダ内で要素の”small”属性に該当する値を指定して、myClaudiaInfoオブジェクトに追加していきます。
claudiaListBoxのItemsSourceプロパティにmyClaudiaInfoオブジェクトを指定します。これでリストボックスにクラウディアの画像が表示されます。

次に、XElement.LoadメソッドでXMLファイル文書(sound.xml)を読み込みます。
文字列型の新しいリストである、soundListオブジェクトを作成します。
Descendantsメソッドですべての子孫要素コレクションに対して変数resultに要素の内容を格納しながら、soundListオブジェクトに要素の属性”word”の値をAddメソッドで追加していきます。
soundListBoxのItemsSourceプロパティにsoundListオブジェクトを指定します。これでリストボックスにクラウディアに喋らす言葉の一覧が表示されます。

01Private Async Sub DataShow()
02  Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
03  Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("ClaudiaData2", CreationCollisionOption.OpenIfExists)
04  Dim myFile = Await mySubFolder.GetFilesAsync()
05  If myFile.Count > 0 Then
06    Dim myXmlList As New List(Of String)
07    For Each fileResult As StorageFile In myFile
08      myXmlList.Add(Path.GetFileNameWithoutExtension(fileResult.Path) & ".xml")
09    Next
10    fileListBox.ItemsSource = myXmlList
11  Else
12    fileListBox.SelectedIndex = -1
13    fileListBox.ItemsSource = Nothing
14  End If
15 
16  xmldoc = XElement.Load("claudia.xml")
17  Dim myClaudiaInfo As New List(Of ClaudiaInfo)
18  For Each result In From c In xmldoc.Descendants("Item") Select c
19    With myClaudiaInfo
20      .Add(New ClaudiaInfo With {.ClaudiaImage = "ms-appx:///Images/" & result.Attribute("small").Value})
21    End With
22 
23  Next
24  claudiaListBox.ItemsSource = myClaudiaInfo
25  soundXml = XElement.Load("sound.xml")
26  Dim soundList As New List(Of String)
27  For Each result In From c In soundXml.Descendants("Item") Select c
28    soundList.Add(result.Attribute("word").Value)
29  Next
30  soundListBox.ItemsSource = soundList
31End Sub

[画像読み込み(jpgファイル)ボタンがタップされた時の処理

ユーザーがファイルを開いて選択できるようにするUI要素を表す、新しいFileOpenPickerクラスのインスタンスmyFileOpenPickerオブジェクトを作成します。

ファイルオープンピッカーが項目を表示するために使用する表示モードを設定するViewModeプロパティにPickerViewMode.Thumbnail(1組の縮小イメージ)を指定します。

ファイルを検索する際の初期位置を設定する、SuggestedStartLocationプロパティにピクチャライブラリを指定します。

FileTypeFilter.Addメソッドで、ファイルオープンピッカーが表示するファイルの種類を追加します。この場合は.jpgを指定しています。
PickSingleFileAsyncメソッドで、ユーザーが1つのファイルを選択できるようにファイルピッカーを表示し、メンバ変数myPersonalImageで参照します。

myPersonalImage.Pathでは絶対パス付きのファイル名が返されますので、Path.GetFileNameWithoutExtensionメソッドで、パスと拡張子を除いたファイル名を取得し、再度”.xml”という拡張子を追加しています。
そのファイル名をメンバ変数myFileNameに格納しておきます。

新しいBitmapImageのインスタンスmyBmpオブジェクトを作成します。
SetSourceメソッドにAwait myPeronalImage.OpenReadAsyncと指定して、ファイルの内容を読むために、現在のファイルのランダムアクセスストリームを開いて、BitmapSourceのソースイメージに設定します。

新しいImageのインスタンスmyImageオブジェクトを作成します。
Widthに640、Heightに480と指定し、SourceプロパティにmyBmpオブジェクトを指定します。
Canvas1にAddメソッドでmyImageオブジェクトを指定します。Claudiaフォルダから選択した画像が表示されます。
クラウディアの画像の表示されているリストボックスの使用を可能にします。

非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

01Private Async Sub readButton_Click(sender As Object, e As RoutedEventArgs) Handles readButton.Click
02  Try
03    Canvas1.Children.Clear()
04    Dim myFileOpenPicker As New FileOpenPicker
05    myFileOpenPicker.ViewMode = PickerViewMode.Thumbnail
06    myFileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary
07    myFileOpenPicker.FileTypeFilter.Add(".jpg")
08    myPeronalImage = Await myFileOpenPicker.PickSingleFileAsync()
09    myFileName = Path.GetFileNameWithoutExtension(myPeronalImage.Path) & ".jpg"
10    If myPeronalImage Is Nothing = False Then
11      Dim myBmp As New BitmapImage
12      myBmp.SetSource(Await myPeronalImage.OpenReadAsync)
13      Dim myImage As New Image
14      With myImage
15        .Width = 640
16        .Height = 480
17        .Source = myBmp
18      End With
19      Canvas1.Children.Add(myImage)
20      claudiaListBox.IsEnabled = True
21    End If
22  Catch
23    claudiaListBox.IsEnabled = False
24    Exit Sub
25  End Try
26End Sub

クラウディアの表示されているリストボックスから任意のクラウディアの画像が選択された時の処理

クラウディアの画像が選択されている場合は、音声の文字列が表示されているリストボックスの使用を可能とし、それ以外は不可とします。
メンバ変数claudiaImageFileNameにclaudia.xmlファイル内の要素が、claudiaListBoxより選択された項目のインデックスに該当する、属性”Large”の値を取得して格納します。
クラウディアの画像をピンチで拡大縮小しドラッグを可能にするclaudiaShowプロシージャを実行します。

01Private Sub claudiaListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles claudiaListBox.SelectionChanged
02  Try
03    If claudiaListBox.SelectedIndex >= 0 Then
04      soundListBox.IsEnabled = True
05    Else
06      soundListBox.IsEnabled = False
07    End If
08    claudiaImageFileName = xmldoc.Descendants("Item")(claudiaListBox.SelectedIndex).Attribute("Large").Value
09    claudiaShow()
10  Catch
11    Exit Sub
12  End Try
13End Sub

クラウディアに喋らす言葉の一覧から、任意の言葉が選択された時の処理

任意の言葉が選択された場合は、Saveアイコンの使用を可能にします。それ以外は使用を不可とします。
メンバ変数SoundFileに、読み込んだsound.xmlファイルの要素で、soundListBoxより選択された項目のインデックスに該当する、属性”wav”の値を取得して格納します。

01Private Sub soundListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles soundListBox.SelectionChanged
02  Try
03    If soundListBox.SelectedIndex >= 0 Then
04      saveButton.IsEnabled = True
05    Else
06      saveButton.IsEnabled = False
07    End If
08    SoundFile = soundXml.Descendants("Item")(soundListBox.SelectedIndex).Attribute("wav").Value
09  Catch
10    Exit Sub
11  End Try
12End Sub

クラウディアの画像をピンチで拡大縮小し、ドラッグする処理

GetFileFromApplicationUriAsyncメソッドで、Imagesフォルダ内のclaudiaImageFileNameメンバ変数に格納されているクラウディアの画像を取得し、メンバ変数claudiaImageで参照しておきます。

新しいBitmapImageのインスタンスmyBmpオブジェクトを作成します。
SetSourceメソッドにAwait claudiaImage.OpenReadAsyncと指定して、claudiaImage内のファイルを開き、BitmapSourceのソースイメージに設定します。
新しいImageのインスタンスmyClaudiaImageオブジェクトを作成し、Widthに246、Heightに760と指定します。
SourceプロパティにmyBmpオブジェクトを指定します。
UIElementの描画位置に影響する変換情報設定するRenderTransformプロパティに、オブジェクトに複数の変換操作を適用するCompositeTransformを指定します。
ジェスチャとともにUIElementの動作および操作に使用されるManipulationModeプロパティに、すべての対話モードを有効にする、ManipulationModes.Allを指定します。
CanvasにmyClaudiaImageオブジェクトを追加します。クラウディアの画像が表示されます。

AddHandlerステートメントで、myClaudiaImageオブジェクトの操作中に、入力デバイスが位置を変更した時に発生するManipulationDeltaイベントにイベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。

TranslateXとTranslateYでx軸とy軸にそって並行移動する距離を設定します。

ScaleXとScaleYでオブジェクトを拡大縮小する値を設定します。

クラウディアの画像一覧が表示されているListBoxの使用を不可とします。

非同期処理で行われるためメソッドの先頭にAsyncを追加します。

01Private Async Sub claudiaShow()
02  claudiaImage = Await StorageFile.GetFileFromApplicationUriAsync(New Uri("ms-appx:///Images/" & claudiaImageFileName))
03  Dim myBmp As New BitmapImage
04  myBmp.SetSource(Await claudiaImage.OpenReadAsync)
05  myClaudiaImage = New Image
06  With myClaudiaImage
07    .Width = 246
08    .Height = 760
09    .Source = myBmp
10    .RenderTransform = New CompositeTransform
11    .ManipulationMode = ManipulationModes.All
12  End With
13  Canvas1.Children.Add(myClaudiaImage)
14 
15  AddHandler myClaudiaImage.ManipulationDelta, Sub(mySender As Object, myArgs As ManipulationDeltaRoutedEventArgs)
16      myTrans = DirectCast(myClaudiaImage.RenderTransform, CompositeTransform)
17      myTrans.TranslateX = myTrans.TranslateX + myArgs.Delta.Translation.X
18      myTrans.TranslateY = myTrans.TranslateY + myArgs.Delta.Translation.Y
19      myTrans.ScaleX = myTrans.ScaleX * myArgs.Delta.Scale
20      myTrans.ScaleY = myTrans.ScaleY * myArgs.Delta.Scale
21    End Sub
22  claudiaListBox.IsEnabled = False
23End Sub
  • クラウディアが写真に登場してセリフを喋るプログラム

薬師寺国安事務所

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

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