しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

共有コントラクトで参照した StorageItem のサムネイルを取得したら怒られた

共有コントラクトを利用して複数の画像ファイルを受け取るストアアプリを作っていたら VisualStudio が激おこぷんぷん丸

f:id:matatabi_ux:20140202182927p:plain

日本語でお願いします;

問題になったのは下記のコードでした

/// <summary>
/// 他のアプリケーションがこのアプリケーションを介してコンテンツの共有を求めた場合に呼び出されます。
/// </summary>
/// <param name="e">Windows と連携して処理するために使用されるアクティベーション データ。</param>
public async void Activate(ShareTargetActivatedEventArgs e)
{
    this._shareOperation = e.ShareOperation;

    this.shareFolder = await ApplicationData.Current.TemporaryFolder.CreateFolderAsync("ShareFile", CreationCollisionOption.OpenIfExists);
    foreach (var file in await this.shareFolder.GetFilesAsync())
    {
        await file.DeleteAsync();
    }

    if (this._shareOperation.Data.Contains(StandardDataFormats.StorageItems))
    {
        this.Items.Clear();

        var items = await this._shareOperation.Data.GetStorageItemsAsync();
        foreach (var item in items)
        {
            var file = item as StorageFile;
            if (file == null)
            {
                continue;
            }
            var thumnail =  await file.GetThumbnailAsync(ThumbnailMode.SingleItem);
            var bitmap = new BitmapImage();
            bitmap.SetSource(thumnail.CloneStream());

            int width = 240;
            int height = 160;

            if(bitmap.PixelWidth / bitmap.PixelHeight > 1.5 )
            {
                height = bitmap.PixelHeight * 240 / bitmap.PixelWidth;
            }
            else
            {
                width = bitmap.PixelWidth * 160 / bitmap.PixelHeight;
            }

            this.Items.Add(new ItemContainerViewModel() { Content = bitmap,  ColumnSpan = width, RowSpan = height });
        }

    }
}

上記の次の部分で Exception が発生してしまいます

var thumnail =  await file.GetThumbnailAsync(ThumbnailMode.SingleItem);

ASTA は Application Single Thread Apartment の略らしく、UI スレッドのことだと思われます

await しているから UI スレッド以外で サムネイル取得を行っているはず・・・なのになぜこうなるのか?!

どうやらこの StorageFile の呼び出し側が UI スレッドで同期的に待機しているとこうなるらしく・・・

共有コントラクトの送り側の方とこっち側で待機しあってデットロックということなんでしょうか

それならば対策は単純

var thumnail = await Task.Run(async () =>
{
    return await file.GetThumbnailAsync(ThumbnailMode.SingleItem);
});

さらに async を重ねてスレッド外に処理を飛ばせば

f:id:matatabi_ux:20140219074630p:plain

・・・大丈夫でした!