Windows PhoneのLumia 520を買ったよ #wpjp
ついにスマートフォン買いました(日本WP待機ガラケー勢
1万円台と、なんともお財布にやさしいローエンドモデルのLumia 520。
Nokia Lumia 520 (Black 黒) SIMフリー 海外携帯
- 出版社/メーカー: Nokia
- メディア: Wireless Phone Accessory
- この商品を含むブログを見る
6月入って最新のEXPANSYSにLumia 630が並び始めたからどっち買うか迷ったんですけど、Lumia 630も同じくローエンドモデルで大差ないので、お財布にやさしい方を選びました。
Windows Phone 8.1への更新
お皿洗いとかハワイ行ったりしながら3時間くらい。
SDカードの認識
更新後にmicro SDを挿したんですが「見つかりません」と認識されなくて焦った。
冷静にぐぐ……bingって下記を参考に[設定] > [情報] > [電話のリセット]でリセットすると認識されました。
アプリの保存先などをSDカードに設定して一安心。
感想
めっちゃぬるさく。きもちい。容量問題はmicro SDでクリアできるし、感度も速度も問題ないし文句なし!
*1:参加者への教材は素直に羨ましい
DependencyObjectから子要素をたどってBehavior、Actionをみつける
それで何が嬉しいかっていうとActionからサスペンドした時に、Actionを探して復帰することで、簡単に処理を継続できるとかとか。具体的にはFileOpenPicker
用のアクションを作った時とか。
Windows ストアアプリは直接コマンドへ、Windows Phoneは復帰後にページからActionをみつけてコマンドへ。
子要素をたどる
まず、子要素をたどるにはVisualTreeHelper
を使います。しかし、低級すぎて使いにくいので拡張メソッドを用意するといいです。
public static IEnumerable<DependencyObject> Children(this DependencyObject obj) { if (obj == null) throw new ArgumentNullException("obj"); var childrenCount = VisualTreeHelper.GetChildrenCount(obj); for (int i = 0; i < childrenCount; i++) { yield return VisualTreeHelper.GetChild(obj, i); } } public static IEnumerable<DependencyObject> Descendants(this DependencyObject obj) { if (obj == null) throw new ArgumentNullException("obj"); foreach (var child in obj.Children()) { yield return child; foreach (var grandChild in child.Descendants()) { yield return grandChild; } } }
これでpage.Descendants()
なんてやると子要素をごっそり取れます。
Behavior、Actionをみつける
Behavior、Actionは表示要素ではないので子要素の中に入っていません。ここではInteraction.GetBehaviors
を使います。
要素を引数にして関連づけられたBehaviorCollection
が取得できます。ここまでくれば何とかなる!こちらも拡張メソッドを定義します。
public static T FindAction<T>(this DependencyObject obj) where T: IAction { return obj .Descendants() .SelectMany(Interaction.GetBehaviors) .SelectMany(x => { var eventTrigger = x as EventTriggerBehavior; if (eventTrigger != null) { return eventTrigger.Actions; } var dataTrigger = x as DataTriggerBehavior; if (dataTrigger != null) { return dataTrigger.Actions; } return null; }) .OfType<T>() .SingleOrDefault(); }
Behaviorをみつける場合はSelectMany(Interaction.GetBehaviors).OfType
でいいです。Actionをみつける場合はActions
をもつBehaviorから展開する必要があるので、ここではSDKに含まれているBehaviorを対象としました。
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.cs
のOnActivated
で引数が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
に引数として選んだファイルが渡されるのでアプリの用途で処理できます。
サンプル
サンプルは下記で公開しています。
- Citrus.Interactions/Citrus.Interactions/Sample/Sample.Shared at develop · KatsuYuzu/Citrus.Interactions · GitHub
- Views/PickPhotoPage.xaml
- ピクチャーハブの呼び出し
- App.xaml.cs, Views/PickPhotoPage.xaml.cs
- サスペンドからの復帰
- ViewModels/PickPhotoPageViewModel.cs
- ファイルの処理
- Views/PickPhotoPage.xaml
サンプルアプリは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>