ファイル一覧表示

 Metro スタイルアプリでは自由にファイルアクセスはできませんが、ピクチャフォルダー等はアクセスできます。
 アクセスできるフォルダーに関してはフォルダーやファイルの一覧も取得できますので、一覧を取得して表示してみたいと思います。

フォルダー/ファイル一覧の取得(基本)

 フォルダーやファイルの一覧を取得する方法として基本になるのは StorageFolder クラスの GetXXXAsync メソッドを呼び出す事です(XXX には Files、Folders、Items のいずれかが入ります)。
 これらのメソッドを呼び出すと一覧が取得できますので、取得した情報を表示する事ができます。

 この方法で表示する事はできますが、GetXXXAsync メソッドを使用した場合、全ての情報が取得されてからでないと結果が取得できません。
 ファイルの数が多ければ結果が取得できるまで時間がかかり、その間は画面に何も表示できない事になります。

フォルダー/ファイル一覧の取得(表示用)

 一覧を取得するまでに時間がかかる問題を解決するために、仮想化された一覧を取得する方法があります。
 仮想化された一覧とは、生成された時には情報を持っておらず、生成後に順次情報を取得していくようになっている物です。
 仮想化された一覧を使う事で取得できた物から順次表示していくようにする事ができます。

 仮想化された一覧を取得するためには FileInformationFactory クラスを使用します。 FileInformationFactory クラスには GetVirtualizedXXXVector というメソッドがあり、このメソッドで仮想化された一覧が返ってきます。
 生成時には情報取得を行わずすぐに制御が返されるため、メソッドも非同期にはなっていません。

サンプル作成

 一覧取得方法がわかったので、サンプルを作成して確認してみます。
 今回は“分割アプリケーション”のテンプレートを改造します。

 サンプルではピクチャフォルダーにアクセスしたいと思いますので“画像ライブラリ”の機能を追加します。

 まずは画面の変更を行います。
 一覧で取得できる情報は FolderInformation または FileInformation になりますので、これらのクラスに存在する Thumbnail プロパティを使って画像を表示し、Name プロパティを使ってフォルダー名またはファイル名を表示したいと思います。

 ここで問題になるのは、Thumbnail プロパティは StorageItemThumbnail という IRandomAccessStream 等のインターフェイスを持った型であり、そのままでは画面に表示できないという点です。
 このため、Thumbnail を表示できる型に変換する Converter を用意します。
 ここでは“StorageDataSource and GetVirtualizedFilesVector sample”というサンプルに含まれている ThumbConverter クラスを使用します。
 実装は以下の通りです。

public class ConverterBase : IValueConverter
{
    public virtual object Convert(object value, Type targetType, object paraer, string culture) { return null; }
    public virtual object ConvertBack(object value, Type targetType, object parameter, string culture) { return null; }
}

public class ThumbConverter : ConverterBase
{
    public override object Convert(object value, Type targetType, object parameter, string culture)
    {
        if (value != null)
        {
            IRandomAccessStream thumbnailStream = value as IRandomAccessStream;
            BitmapImage bi = new BitmapImage();
            bi.SetSource(thumbnailStream);

            return bi;
        }
        return DependencyProperty.UnsetValue;
    }
}

 処理内容としては IRandomAccessStream を BitmapImage のソースとして設定して、その BitmapImage を返すようになっています。

 このコンバーターも使って画像と名前を表示する DataTemplate を作成します。
 元々 GridView の表示に使われている DataTemplate は Standard250x250ItemTemplate という物です。
 Common/StandardStyles.xaml に定義されていますので、この定義を ItemsPage.xaml 内にコピーして以下のように変更します。

<local:ThumbConverter x:Key="myThumbConverter" />

<DataTemplate x:Key="FileItemTemplate">
    <Grid HorizontalAlignment="Left" Width="250" Height="250">
        <Border Background="{StaticResource ListViewItemPlaceholderRectBrush}">
            <Image Source="{Binding Path=Thumbnail, Converter={StaticResource myThumbConverter}}" Stretch="UniformToFill"/>
        </Border>
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundBrush}">
            <TextBlock Text="{Binding Name}" Foreground="{StaticResource ListViewItemOverlaySecondaryTextBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
        </StackPanel>
    </Grid>
</DataTemplate>

 まず、コンバーターを作成しています。
 DataTemplate では Thumbnail プロパティを使って画像を表示し(この時にコンバーターを指定しています)、さらに下部に Name プロパティを使って名前を表示するようにしています。

 続いてソースを改造していきます。
 最初は App.xaml.cs の OnLaunched に一覧を取得して表示するページに渡す処理を追加します。
 ピクチャライブラリ内を検索するためにクエリ(今回はデフォルトの物)を取得して FileInformationFactory クラス生成時に指定し、生成した factory オブジェクトから一覧を取得して ItemsPage に渡します。

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    var library = KnownFolders.PicturesLibrary;
    var query = library.CreateItemQuery();
    var factory = new FileInformationFactory(query, ThumbnailMode.SingleItem, 500, ThumbnailOptions.UseCurrentScale, false);

    var _rootFrame = new Frame();
    _rootFrame.Navigate(typeof(ItemsPage), factory.GetVirtualizedItemsVector());
    Window.Current.Content = _rootFrame;
    Window.Current.Activate();
}

 これで、起動時にピクチャフォルダー直下のフォルダーやファイルが一覧表示されるようになります。

 続いて、ItemsPage.xaml.cs も改造して、フォルダーをクリックしたら、そのフォルダーに移動できるようにします。
 ItemClick イベントのハンドラ(最初から定義されています)を以下のように書き換えます。

void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
    var info = e.ClickedItem as FolderInformation;
    if (info != null)
    {
        var query = info.CreateItemQuery();
        var factory = new FileInformationFactory(query, ThumbnailMode.SingleItem, 500, ThumbnailOptions.UseCurrentScale, false);

        this.Frame.Navigate(typeof(ItemsPage), factory.GetVirtualizedItemsVector());
    }
}

 クリックされた項目が渡されますので、対象がフォルダーだった(FolderInformation にキャスト可能)場合のみ、対象フォルダーに移動します。
 一覧の取得自体は起動時と同じで、対象がクリックされたフォルダーになっているだけです。

実行結果

 変更が終わったので実行してみます。
 起動するとピクチャフォルダー直下のフォルダーやファイルが一覧表示され、フォルダーをクリックするとそのフォルダーに移動できます。

 一覧は仮想化されていますので、表示までに時間がかかる場合があります(枠だけや枠と名前だけ表示されて後から画像が表示される事や、粗い画像が表示されて後から高精細な画像が表示される事があります)。