酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows Store apps(WinRT)で、ピクチャーライブラリ内から画像ファイルを取得してListViewへ表示させる

@garicchi がWindowsストアアプリ開発で悩んでいました。

どうやらピクチャーライブラリ内に格納されている画像をバインディングして表示できない様子です。

そんなことないですよ、デスクトップアプリと比較してできることが限られているWindowsストアアプリでもループ内で画像を取得することができますよ、というためのエントリ。結論から書くと、下図のように取得することができました。

ソースコードは「Imageにピクチャライブラリ内の画像を表示する - がりらぼWP7 ~WindowsPhoneプログラミング情報発信ラボ~」をベースにしています。合わせてお読みください。

画像ライブラリへアクセスする機能を追加(Package.appxmanifest)

ピクチャーライブラリへアクセスするためには、ユーザーへ事前に告知しておく必要があります。ソリューションエクスプローラーにある「Package.appxmanifest」をダブルクリックで開きます。

[機能]タブを開くと、機能一覧が並んでいますので、「画像ライブラリ」にチェックを付けます。これでアプリケーションからピクチャーライブラリの情報を取得することが可能となりました。


XAML(MainPage.xaml)

MainPage.xamlにはListViewを配置しており、ピクチャーライブラリから取得した画像情報のコレクションをListViewへ設定しています。ListViewのItemTemplateにはファイル名とそのファイル名から得られた画像を表示させます。

DataTemplateにて定義されているImageには「Image」をバインドし、TextBlockにはDisplayNameをバインドしています。

<Page
    x:Class="PicturesLibraryFilesSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PicturesLibraryFilesSample"
    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}">
        <StackPanel>
            <Button x:Name="btnLoadPictures" Content="load pictures library" Click="btnLoadPictures_Click" />
        </StackPanel>

        <ListView x:Name="listView" HorizontalAlignment="Left" Margin="188,0,0,0" VerticalAlignment="Stretch" Width="600">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Image, Mode=TwoWay}"  Width="300" Height="200" Stretch="Uniform" />
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="{Binding DisplayName}" />
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </Grid>
</Page>

ページの実装(MainPage.xaml.cs)

ここもシンプルにOnNavigatedToメソッドで、listViewのItemsSourceプロパティに画像情報のコレクションfileNameListを設定しています。

そしてボタンがクリックされれるとClickイベントハンドラのbtnLoadPictures_Clickメソッドが動き、ピクチャー ライブラリからPNGファイルのリストを検索し、画像情報をfileNameListに追加していきます。

fileNameListにアイテム(画像情報)が追加されると、ListViewへ「アイテムが追加されたよー」と通知され、ListViewに更新がかかります。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Windows.Storage;
using Windows.Storage.Search;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace PicturesLibraryFilesSample
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        ObservableCollection<PictureInfo> fileNameList = new ObservableCollection<PictureInfo>();

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            listView.ItemsSource = fileNameList;
        }

        private async void btnLoadPictures_Click(object sender, RoutedEventArgs e)
        {
            // ピクチャー ライブラリからPNGファイルのリストを検索する
            var query = KnownFolders.PicturesLibrary.CreateFileQuery(CommonFileQuery.OrderByName);
            query.ApplyNewQueryOptions(new QueryOptions(
                CommonFileQuery.OrderByName, new List<string>(){".png"}));
            var files = await query.GetFilesAsync();

            // 得られたピクチャーライブラリ内のリストからファイル名を取得し、
            // ListViewにバインドされたfileNameListへ追加する
            foreach (StorageFile file in files)
            {
                var pi = new PictureInfo(file.DisplayName, file.Name);
                fileNameList.Add(pi);
                pi.LoadAsync();
            }
        }
    }
}

バインディングする画像情報アイテム(PictureInfo)

バインディングする画像情報のクラスを実装します。LoadAsyncメソッドを呼び出すことで、ファイル名からBitmapImageオブジェクトを生成します。

先ほどのbtnLoadPictures_Clickメソッドの中で、画像情報のコレクションに追加した後にLoadAsyncメソッドを読んでいます。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.UI.Xaml.Media.Imaging;

namespace PicturesLibraryFilesSample
{
    public class PictureInfo : INotifyPropertyChanged 
    {
        public PictureInfo() { }
        public PictureInfo(string displayName, string fileName)
        {
            DisplayName = displayName;
            FileName = fileName;
        }

        public async void LoadAsync()
        {
            if (Image == null)
            {
                Image = new BitmapImage();
            }

            var folder = await KnownFolders.PicturesLibrary.GetFileAsync(FileName);
            var stream = await folder.OpenReadAsync();
            if (stream == null)
            {
                // ファイルの読み出しに失敗
                return;
            }

            Image.SetSource(stream);

            OnPropertyChanged("Image");
        }

        public string DisplayName { get; set; }
        public string FileName { get; set; }
        public BitmapImage Image { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

    }
}

以上で終わりです。ここでは、ピクチャーライブラリ内から画像ファイルを取得してListViewへ表示させる方法をご紹介させて頂きましたが、大体このような方法でインターネット上のファイルをダウンロードさせたりすることが出来るはずです。