KatsuYuzuのブログ

.NET の開発をメインとした日記です。

Windows Phone 8.1 でピクチャーハブから写真を選択する #wpdev_jp

Windows Phone 8.1ではメモリが少ないデバイス用にいくつかのAPIで、アプリがサスペンドして、ユーザー操作後に復帰するようになっています。開発者的には気を遣うことが増えたわけですが、ユーザーフレンドリー。
そして、Windows ストアアプリとコードを共有するユニバーサル アプリでは、それらのAPIに対してWindows ストアアプリ用のHogeAsyncとWindows Phone用のHogeAndContinueが提供されています。HogeAndContinueを呼ぶとサスペンドするので、アプリの復帰処理を適切に行う必要があります。

ピクチャーハブから写真を選択する

従来のWindows Phoneアプリ(ここではWindows Phone 8以前)ではPhotoChooserTaskを使用しますが、ここではWindows ストアアプリと同様にFileOpenPickerを使用します。

ピクチャーハブの呼び出し

まず、拡張子や参照場所などの準備をします。

var picker = new FileOpenPicker
{
    .ViewMode = viewMode,
    .SuggestedStartLocation = PickerLocationId.PicturesLibrary
};

foreach (var extension in SupportedExtensions)
{
    // .jpgとか.pngとか
    picker.FileTypeFilter.Add(extension);
}

次に、対象とするプロジェクトに合わせた#ifディレクティブでAPIを呼びます。

#if WINDOWS_APP
    await picker.PickSingleFileAsync();
#else
    picker.PickSingleFileAndContinue();
#endif

サスペンドからの復帰

App.xaml.csOnActivatedで引数がIContinuationActivatedEventArgsか調べて処理します。

protected override void OnActivated(IActivatedEventArgs args)
{
    // 中略: ページの復帰処理

    var e = args as IContinuationActivatedEventArgs;
    if (e != null)
    {
        // 記事末の補助ライブラリのクラス
        new ContinuationManager().Continue(e);
    }
}

ライブラリのContinue内では、復帰したページがどのAPIからの復帰に対応しているか判別しています。

var fileOpenPickerPage = rootFrame.Content as IFileOpenPickerContinuable;
if (fileOpenPickerPage != null)
{
    fileOpenPickerPage.ContinueFileOpenPicker(args as FileOpenPickerContinuationEventArgs);
}

これでPageに引数として選んだファイルが渡されるのでアプリの用途で処理できます。

サンプル

サンプルは下記で公開しています。

サンプルアプリはPrismベースで、@okazukiさんのPrismAdapterを使用しています。

補助ライブラリ

サンプルの一部は開発中のライブラリ(Citrus.Interactions)を使用したものです。
ライブラリを使用すると、ピクチャーハブの呼び出しはPickPhotoActionというトリガーアクションを配置するだけでいいです。

<Button Content="PickPhotoAction">
    <Interactivity:Interaction.Behaviors>
        <Core:EventTriggerBehavior EventName="Click">
            <Interactions:PickPhotoAction CallbackCommand="{Binding PickPhotoCommand}" />
        </Core:EventTriggerBehavior>
    </Interactivity:Interaction.Behaviors>
</Button>