画像ファイルを表示するには?[Win 8]WinRT/Metro TIPS

Windowsストア・アプリでは、プロジェクトに含まれていない画像を画面上に表示する手法がいくつか存在する。その方法を整理して説明する。

» 2012年10月11日 15時22分 公開
[山本康彦BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次はこちら

 Visual Studioのプロジェクトに含まれている画像ファイルをImageコントロール(Windows.UI.Xaml.Controls名前空間)に表示するのは、簡単だ。しかし、それ以外の場所に置かれている画像ファイルを表示しようとすると、行き詰まってしまうことがあるのではないだろうか?

 Windowsストア・アプリ(旧称: Metroスタイル・アプリ)では、ファイルの位置を特別なプロトコルを使ったURIでも表現できたり、XAMLコードでもC#/VBコードでも同じ処理が実現できたりと、画像ファイルを表示する手法が多く存在する。

 そこで本稿では、画像ファイルの置き場所に応じた表示方法を整理して紹介する。

事前準備

 Windows 8(以降、Win 8)向けのWindowsストア・アプリを開発するには、Win 8とVisual Studio 2012(以降、VS 2012)が必要である。これらを準備するには、第1回のTIPSを参考にしてほしい。本稿ではWin 8とVS 2012 Expressを使用している。

画像ファイルの場所と表示方法

 最初に、ファイルの場所と画像表示方法の関係を整理して示しておく。

画像ファイルの場所 XAMLコード C#/VBコード
プロジェクト埋め込み(インストール・フォルダ) ms-appx: Uriで指定してBitmapImageオブジェクトを作成
アプリケーション・データ ms-appdata: Uriで指定。
または、ストリームからBitmapImageオブジェクトを作成
それ以外(KnownFoldersクラスやFileOpenPickerクラスでユーザーが選択) (不可) ストリームからBitmapImageオブジェクトを作成
ファイルの場所と画像表示方法の関係

 上記の表に記載されている「インストール・フォルダ」というのは、アプリがインストールされた場所のことであり、読み出せるが書き込みはできない。プロジェクトに含まれているコンテンツ・ファイルも、ここにインストールされる。

 「アプリケーション・データ」というのは、「\Users\{user}\AppData\Local\Packages\{app-id}\」(={user}はユーザー名、{app-id}はアプリのパッケージ名)の直下に作られる、「LocalState」/「RoamingState」/「TempState」という3つのフォルダに置かれたファイルである。アプリケーション・データのファイルは、アプリから自由に読み書きできる。

 それ以外の場所は、アプリから勝手に読み書きすることはできない。

 まず、アプリケーション・マニフェストの[機能]で[画像ライブラリ]などを許可してやれば、それに応じてKnownFoldersクラス(Windows.Storage名前空間)を介したアクセスができる。例えば[画像ライブラリ]ならば、KnownFolders. PicturesLibraryプロパティを利用して読み書きできる。

 次に、FileOpenPickerクラス(Windows.Storage.Pickers名前空間)を使ってユーザーに選択してもらったファイルにもアクセスが可能だ。

 以降では、この表のそれぞれのパターンを説明していく。前提として、「Sample.png」という名前の画像ファイルが、プロジェクトのAssetsフォルダと、アプリケーション・データのLocalStateフォルダに置いてあるものとする。

プロジェクト埋め込みの画像をXAMLコードで表示するには?

 ImageコントロールのSourceプロパティに指定するだけで、画像が表示できる。この場合は、プロトコルを指定しなくてもよい。

<StackPanel Grid.Column="0">
  <Image Source="/Assets/Sample.png" />
  <TextBlock Text="埋め込みリソース: XAML で Source プロパティを指定 (プロトコルなし)" />
</StackPanel>


埋め込み画像を表示するXAMLコード(プロトコル指定なし)


 上のように、Imageコントロールに埋め込み画像を表示させるのは簡単だ。しかしこの書き方は、次に示す「ms-appx:」プロトコルの省略記法だと思ってほしい。

<StackPanel Grid.Column="1">
  <Image Source="ms-appx:///Assets/Sample.png" />
  <TextBlock Text="埋め込みリソース: XAML で Source プロパティを指定 (プロトコルあり)" />
</StackPanel>


埋め込み画像を表示するXAMLコード(プロトコル指定あり)


【補足】プロトコルの有無について

 以下は、意味は異なるが、実際には同じフォルダになる。

  • 「ms-appx:」プロトコル: インストール・フォルダが基準
  • プロトコル無し: アプリが起動されたフォルダが基準

プロジェクト埋め込みの画像をC#/VBコードで表示するには?

 画像ファイルの位置をUriクラス(System名前空間)のオブジェクトで表現し、BitmapImageクラス(Windows.UI.Xaml.Media.Imaging名前空間)のオブジェクトを作成して、ImageコントロールのSourceプロパティにセットする。プロトコルは省略できない。

private void LoadFromFileUri2()
{
  var fileUri = "ms-appx:///Assets/Sample.png";
  var bitmap = new BitmapImage(new Uri(fileUri));
  this.image2.Source = bitmap;
}


Private Sub LoadFromFileUri2()
  Dim fileUri = "ms-appx:///Assets/Sample.png"
  Dim bitmap = New BitmapImage(New Uri(fileUri))
  Me.image2.Source = bitmap
End Sub


埋め込み画像を表示するコード(上:C#、下:VB)


 なお、Windows.ApplicationModel.Package.Current.InstalledLocationプロパティを使ってストリームを開き、BitmapImageオブジェクトを作成することも可能ではある(後述の「アプリケーション・データの画像をコードで表示するには?」の2番目と同様の方法)。しかし、通常は上記の方法で十分なはずだ。

アプリケーション・データの画像をXAMLコードで表示するには?

 やはり、ImageコントロールのSourceプロパティに指定するだけである。ただし、アプリケーション・データには「ms-appdata:」プロトコルを利用する。

<StackPanel Grid.Column="3">
  <Image Source="ms-appdata:///local/Sample.png" />
  <TextBlock Text="LocalFolderのファイル: XAML で Source プロパティを指定 (プロトコルあり)" />
</StackPanel>


アプリケーション・データの画像を表示するXAMLコード


 フォルダ名として、本来の「LocalState」ではなく「local」と指定しなければならないことに注意が必要だ。「RoamingState」/「TempState」は、「roaming」/「temporary」となる。

アプリケーション・データの画像をC#/VBコードで表示するには?

 埋め込み画像と同様に、画像ファイルをUriオブジェクトで指定する方法が使える。

private void LoadFromFileUri4()
{
  var fileUri = "ms-appdata:///local/Sample.png";
  var bitmap = new BitmapImage(new Uri(fileUri));
  this.image4.Source = bitmap;
}


Private Sub LoadFromFileUri4()
  Dim fileUri = "ms-appdata:///local/Sample.png"
  Dim bitmap = New BitmapImage(New Uri(fileUri))
  Me.image4.Source = bitmap
End Sub


アプリケーション・データの画像を表示するコード1(上:C#、下:VB)
ファイル名が固定の場合はこれでよい


 実際には、アプリケーション・データの画像は動的に変えることが多いので、次のようにしてファイル名からストリームを開いてBitmapImageオブジェクトにセットする方法を使うことが多いだろう。

private async void LoadFromApplicationData5()
{
  var fileName = "Sample.png";
  StorageFile file
    = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
  var stream = await file.OpenReadAsync();

  var bitmap = new BitmapImage();
  bitmap.SetSource(stream);
  this.image5.Source = bitmap;
}


Private Async Sub LoadFromApplicationData5()
  Dim fileName = "Sample.png"
  Dim file As StorageFile _
    = Await ApplicationData.Current.LocalFolder.GetFileAsync(fileName)
  Dim stream = Await file.OpenReadAsync()

  Dim bitmap = New BitmapImage()
  bitmap.SetSource(stream)
  Me.image5.Source = bitmap
End Sub


アプリケーション・データの画像を表示するコード2(上:C#、下:VB)
ファイル名が可変の場合はこのようにする


 なお、ApplicationDataクラス(Windows.Storage名前空間)では、本来の「LocalState」というフォルダ名ではなく「LocalFolder」という名前のプロパティになっているが、同じフォルダである。「RoamingState」/「TempState」は、「RoamingFolder」/「TemporaryFolder」となる。

それ以外の場所の画像をC#/VBコードで表示するには?

 画像ファイルをUriオブジェクトで指定する方法は使えない。そのため、XAMLコードだけで表示することはできず、C#/VBコードでストリームを開いてBitmapImageオブジェクトにセットすることになる。ここではFileOpenPickerクラスを使う例を紹介する。

private async void StackPanel6_Tapped(object sender, TappedRoutedEventArgs e)
{
  var picker = new FileOpenPicker();
  picker.FileTypeFilter.Add(".png");
  StorageFile file = await picker.PickSingleFileAsync();
  if (file == null)
    return;

  IRandomAccessStream stream = await file.OpenReadAsync();

  var bitmap = new BitmapImage();
  bitmap.SetSource(stream);
  this.image6.Source = bitmap;
}


Private Async Sub StackPanel6_Tapped(sender As Object, e As TappedRoutedEventArgs)
  Dim picker = New FileOpenPicker()
  picker.FileTypeFilter.Add(".png")
  Dim file As StorageFile = Await picker.PickSingleFileAsync()
  If (file Is Nothing) Then
    Return
  End If

  Dim stream As IRandomAccessStream = Await file.OpenReadAsync()

  Dim bitmap = New BitmapImage()
  bitmap.SetSource(stream)
  Me.image6.Source = bitmap
End Sub


FileOpenPickerでユーザーが選択した画像を表示するコード(上:C#、下:VB)


コントロールの背景に画像をC#/VBコードで表示するには?

 参考までに、Gridコントロール(Windows.UI.Xaml.Controls名前空間)などの、Backgroundプロパティを持っているコントロールの背景に画像を設定する方法も紹介しておこう。

 BitmapImageオブジェクトを持つImageBrushオブジェクト(Windows.UI.Xaml.Media名前空間)を生成すれば、Backgroundプロパティにセットできる。

private void LoadFromFileUri7()
{
  var fileUri = "ms-appx:///Assets/Sample.png";
  var bitmap = new BitmapImage(new Uri(fileUri));

  var brush = new ImageBrush();
  brush.ImageSource = bitmap;
  brush.Stretch = Stretch.None;
  this.grid7.Background = brush;
}


Private Sub LoadFromFileUri7()
  Dim fileUri = "ms-appx:///Assets/Sample.png"
  Dim bitmap = New BitmapImage(New Uri(fileUri))

  Dim brush = New ImageBrush()
  brush.ImageSource = bitmap
  brush.Stretch = Stretch.None
  Me.grid7.Background = brush
End Sub


画像をGridコントロールの背景に表示するコード(上:C#、下:VB)


実行結果

 以上のコードを実装して実行してみた画面を、次に示す。

本稿で説明した8通りのパターンを実装した画面(1366x768)

まとめ

 画像を表示するには、そのファイルの置き場所に応じて適切な手法を使い分けるようにする。次のドキュメントが参考になる。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。