読者です 読者をやめる 読者になる 読者になる

KatsuYuzuのブログ

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

Windows ストアアプリでカメラを起動して写真を撮るトリガーアクション #win8dev_jp

Windows ストアアプリでカメラを起動して写真を撮るトリガーアクション作りました。
f:id:KatsuYuzu:20140310235001p:plain
Blendでぽとぺたするだけでカメラを扱うことが出来ます。
# 今度nuget化しておきますん。

ライブラリ

2014/03/19 追記

ライブラリ化しました。
Citrus Interactions - Action / Behavior library for WinRT - Home

実装

カメラ起動

カメラ起動部分の実装はとっても簡単です。CameraCaptureUIクラスのCaptureFileAsyncを呼ぶだけ!

/// <summary>
/// 写真をキャプチャします。
/// </summary>
/// <param name="format">キャプチャされた写真を格納する形式を決定します。</param>
/// <returns></returns>
private async static Task<StorageFile> CaputurePhotoAsync(CameraCaptureUIPhotoFormat format)
{
    var camera = new CameraCaptureUI();

    camera.PhotoSettings.Format = format;

    return await camera.CaptureFileAsync(CameraCaptureUIMode.Photo);
}

アクション

トリガーから呼ばれるアクションです。カメラ起動の非同期アクションを呼び出して、ICommandのCanExecuteとExecuteを実行します。

/// <summary>
/// アクションを実行します。
/// </summary>
/// <param name="sender">使用されません。</param>
/// <param name="parameter">使用されません。</param>
/// <returns>アクションの結果を返します。</returns>
public object Execute(object sender, object parameter)
{
    if (this.CallbackCommand == null)
    {
        // 定数 0(アクションの決まり?)
        return Result.Canceled;
    }

    // 警告の抑制
    var task = ExecuteAsync(this.PhotoFormat, this.CallbackCommand);

    // 定数 1
    return Result.Executed;
}

/// <summary>
/// アクションを実行します。
/// </summary>
/// <param name="format">キャプチャされた写真を格納する形式を決定します。</param>
/// <param name="callbakCommand">アクションの実行後に呼び出す <see cref="ICommand"/></param>
/// <returns></returns>
private async static Task ExecuteAsync(CameraCaptureUIPhotoFormat format, ICommand callbakCommand)
{
    var photo = await CaputurePhotoAsync(format);

    if (!callbakCommand.CanExecute(photo))
    {
        return;
    }

    callbakCommand.Execute(photo);
}
余談

警告出る部分って下記と等価?どっちがいいんだろ。

Task.Run(() => ExecuteAsync(this.PhotoFormat, this.CallbackCommand));

関数に分離しないやりかたは可読性に難が。

Task.Run(async () =>
{
    var photo = await CaputurePhotoAsync(format);
    hogehoge
}

ViewModel

撮影後に呼ばれるコマンドと処理。Model作るまでもないサンプルなので気にせず処理。

private DelegateCommand<StorageFile> _selectedPhotoCommand;
public DelegateCommand<StorageFile> SelectedPhotoCommand
{
    get
    {
        return this._selectedPhotoCommand 
            ?? (this._selectedPhotoCommand = new DelegateCommand<StorageFile>(
                x =>
                {
                    var task = LoadImage(x);
                },
                x =>
                {
                    return x != null;
                }));
    }
}

private async Task LoadImage(StorageFile file)
{
    this.ImageSource = await WriteableBitmapLoadExtensions.FromFileAsync(file);
}

WriteableBitmapLoadExtensionsは後述の参考「酢ろぐ」をご参照ください。

XAML

ボタンなどの任意のコントロールにぽとぺた。

<Interactivity:Interaction.Behaviors>
    <Core:EventTriggerBehavior EventName="Click">
        <Behavior:CaputurePhotoAction CallbackCommand="{Binding SelectedPhotoCommand}" />
    </Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>

実行

f:id:KatsuYuzu:20140311004257j:plain
# くつしたにゃんこかわいい
# プロジェクト作成から実行までの動画じゃないと伝わらない

まとめ

もともと簡単なAPI群が用意されているWindows ストアアプリですが、こうしてパーツ化していくことで使いたい時にサッとぽとぺたプログラミングができます。Silverlightの時も同じようなこと言ってた気がしますが、これがXAMLとBlendの魅力なんですよね。