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

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を指定して非表示としておきます。
<Page
  x:Class="WithClaudia2.DataShowPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:WithClaudia2"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d">
  <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Canvas x:Name="ShowArea" HorizontalAlignment="Left" Height="480" Margin="303,167,0,0" VerticalAlignment="Top" Width="640"/>■(1)
    <MediaElement x:Name="MediaElement1" HorizontalAlignment="Left" Height="58" Margin="1010,394,0,0" VerticalAlignment="Top" Width="280"/>■(2)
    <Button x:Name="playButton" HorizontalAlignment="Left" Height="92" Margin="487,666,0,0" VerticalAlignment="Top" Width="129" Style="{StaticResource PlayAppBarButtonStyle}"/>■(3)
    <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)
    <Button x:Name="delButton" HorizontalAlignment="Left" Height="92" Margin="621,666,0,0" VerticalAlignment="Top" Width="97" Style="{StaticResource DeleteAppBarButtonStyle}"/>■(5)
    <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)
  </Grid>
</Page>
図8:各種コントロールを配置した(クリックで拡大)

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

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

リスト4 (MainWindow.xaml.vb)

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

Imports Windows.Storage.Pickers

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

Imports Windows.Storage.Streams

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

Imports Windows.Storage

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

Public Class ClaudiaInfo
  Property ClaudiaImage As String
End Class

Public NotInheritable Class MainPage
  Inherits Page

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

  Dim claudiaImage As StorageFile

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

  Dim myClaudiaImage As Image

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

  Dim myTrans As CompositeTransform
 
  Dim myFileName As String

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

  Dim xmldoc As XElement

  Dim claudiaImageFileName As String

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

  Dim myPeronalImage As StorageFile

  Dim SoundFile As String

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

  Dim soundXml As XElement
  
  Dim mySelectedFile As String

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

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

  Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    DataShow()
    MyBase.OnNavigatedTo(e)
  End 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オブジェクトを指定します。これでリストボックスにクラウディアに喋らす言葉の一覧が表示されます。

  Private Async Sub DataShow()
    Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("ClaudiaData2", CreationCollisionOption.OpenIfExists)
    Dim myFile = Await mySubFolder.GetFilesAsync()
    If myFile.Count > 0 Then
      Dim myXmlList As New List(Of String)
      For Each fileResult As StorageFile In myFile
        myXmlList.Add(Path.GetFileNameWithoutExtension(fileResult.Path) & ".xml")
      Next
      fileListBox.ItemsSource = myXmlList
    Else
      fileListBox.SelectedIndex = -1
      fileListBox.ItemsSource = Nothing
    End If
 
    xmldoc = XElement.Load("claudia.xml")
    Dim myClaudiaInfo As New List(Of ClaudiaInfo)
    For Each result In From c In xmldoc.Descendants("Item") Select c
      With myClaudiaInfo
        .Add(New ClaudiaInfo With {.ClaudiaImage = "ms-appx:///Images/" & result.Attribute("small").Value})
      End With
 
    Next
    claudiaListBox.ItemsSource = myClaudiaInfo
    soundXml = XElement.Load("sound.xml")
    Dim soundList As New List(Of String)
    For Each result In From c In soundXml.Descendants("Item") Select c
      soundList.Add(result.Attribute("word").Value)
    Next
    soundListBox.ItemsSource = soundList
  End 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を追加します。

  Private Async Sub readButton_Click(sender As Object, e As RoutedEventArgs) Handles readButton.Click
    Try
      Canvas1.Children.Clear()
      Dim myFileOpenPicker As New FileOpenPicker
      myFileOpenPicker.ViewMode = PickerViewMode.Thumbnail
      myFileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary
      myFileOpenPicker.FileTypeFilter.Add(".jpg")
      myPeronalImage = Await myFileOpenPicker.PickSingleFileAsync()
      myFileName = Path.GetFileNameWithoutExtension(myPeronalImage.Path) & ".jpg"
      If myPeronalImage Is Nothing = False Then
        Dim myBmp As New BitmapImage
        myBmp.SetSource(Await myPeronalImage.OpenReadAsync)
        Dim myImage As New Image
        With myImage
          .Width = 640
          .Height = 480
          .Source = myBmp
        End With
        Canvas1.Children.Add(myImage)
        claudiaListBox.IsEnabled = True
      End If
    Catch
      claudiaListBox.IsEnabled = False
      Exit Sub
    End Try
  End Sub

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

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

  Private Sub claudiaListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles claudiaListBox.SelectionChanged
    Try
      If claudiaListBox.SelectedIndex >= 0 Then
        soundListBox.IsEnabled = True
      Else
        soundListBox.IsEnabled = False
      End If
      claudiaImageFileName = xmldoc.Descendants("Item")(claudiaListBox.SelectedIndex).Attribute("Large").Value 
      claudiaShow()
    Catch
      Exit Sub
    End Try
  End Sub

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

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

  Private Sub soundListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles soundListBox.SelectionChanged
    Try
      If soundListBox.SelectedIndex >= 0 Then
        saveButton.IsEnabled = True
      Else
        saveButton.IsEnabled = False
      End If
      SoundFile = soundXml.Descendants("Item")(soundListBox.SelectedIndex).Attribute("wav").Value
    Catch
      Exit Sub
    End Try
  End 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を追加します。

  Private Async Sub claudiaShow()
    claudiaImage = Await StorageFile.GetFileFromApplicationUriAsync(New Uri("ms-appx:///Images/" & claudiaImageFileName))
    Dim myBmp As New BitmapImage
    myBmp.SetSource(Await claudiaImage.OpenReadAsync)
    myClaudiaImage = New Image
    With myClaudiaImage
      .Width = 246
      .Height = 760
      .Source = myBmp
      .RenderTransform = New CompositeTransform
      .ManipulationMode = ManipulationModes.All
    End With
    Canvas1.Children.Add(myClaudiaImage)
 
    AddHandler myClaudiaImage.ManipulationDelta, Sub(mySender As Object, myArgs As ManipulationDeltaRoutedEventArgs)
        myTrans = DirectCast(myClaudiaImage.RenderTransform, CompositeTransform)
        myTrans.TranslateX = myTrans.TranslateX + myArgs.Delta.Translation.X
        myTrans.TranslateY = myTrans.TranslateY + myArgs.Delta.Translation.Y
        myTrans.ScaleX = myTrans.ScaleX * myArgs.Delta.Scale
        myTrans.ScaleY = myTrans.ScaleY * myArgs.Delta.Scale
      End Sub
    claudiaListBox.IsEnabled = False
  End 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メルマガ会員のサービス内容を見る

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