酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows PhoneでWebClientを使ってWebページを取得する

ウェブコンテンツをダウンロードする場合、WebClientクラスを使用すると簡単です。

WebClientを使ってWebページを取得する

ダウンロード完了処理をイベントハンドラでおこなう

DownloadStringCompletedイベントハンドラを設定しておいて、DownloadStringAsyncメソッドで非同期ダウンロードを開始します。

// using System.Net;
// using Microsoft.Phone.Reactive;

// 一番シンプルなケース
private void button1_Click(object sender, RoutedEventArgs e) {
    var client = new WebClient();
    client.DownloadStringCompleted += client_DownloadStringCompleted;

    // ダウンロードを開始する
    client.DownloadStringAsync(new Uri("http://search.twitter.com/search.atom?q=ch3cooh"));
}

// ダウンロードが完了すると通知されるイベントハンドラ
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
    MessageBox.Show(e.Result);
}

Reactive Extensionsを使ってダウンロードしたデータを処理する

以下のソースコードの通り、Rxを使うとダウンロードした後の処理も含めてClickイベントハンドラ内で書いてしまうことができます。

Rxを使うには、あらかじめソリューションエクスプローラーにて[参照の追加]を選択し、参照の追加ダイアログを表示させ「System.Observable」と「Microsoft.Phone.Reactive」を選択しておきます。

// using System.Net;
// using Microsoft.Phone.Reactive;

// Rxを使ったケース
private void button2_Click(object sender, RoutedEventArgs e) {

    var client = new WebClient();
    Observable.FromEvent<DownloadStringCompletedEventArgs>(client, "DownloadStringCompleted")
        .Select(evt => evt.EventArgs.Result)
        .Subscribe((msg => MessageBox.Show(msg)));

    // ダウンロードを開始する
    client.DownloadStringAsync(new Uri("http://search.twitter.com/search.atom?q=ch3cooh"));
}

Windows PhoneでZXing Barcode Scanning Libraryを使ってバーコードを読み込む(Windows Phone OS 7.1 ~)

カメラプレビューから直接プレビューフレームを取り出せ無かったWindows Phone OS 7.0では、CameraCaptureTaskを利用してバーコードの読み込みを行いました。詳細については、ZXing Barcode Scanning Libraryを使ってバーコードを読み込む(Windows Phone OS 7.0)をご覧ください。

ここでは、PhotoCameraクラスを利用してカメラプレビューから映像を取り出しながら、解析を行いリアルタイム取り込みをしてみましょう。今回読み取るバーコードはこれです。

f:id:ch3cooh393:20140818122349p:plain

前述した通り、PhotoCameraから取り込んだ映像を矩形PreviewRectangleに表示して、取り込んだ映像をリアルタイムに解析し、バーコードの認識が出来ればリストボックスBarcodeListBoxへ解析結果を追加していきます。

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <!-- この矩形にカメラプレビューを表示する -->
    <Rectangle x:Name="PreviewRectangle" Margin="0">
        <Rectangle.Fill>
            <VideoBrush x:Name="PreviewBrush" />
        </Rectangle.Fill>
    </Rectangle>
    <ListBox Name="BarcodeListBox" />
</Grid>

MainPageクラスにPhotoCameraのインスタンス変数を追加しました。

    public partial class MainPage : PhoneApplicationPage {

        // コンストラクター
        public MainPage() {
            InitializeComponent();
        }

        PhotoCamera camera = null;

OnNavigatedToにてPhotoCameraクラスのインスタンスを生成します。同時に初期化処理完了のイベントハンドラの設定とPreviewBrushのデータソースとしてcameraを指定します。

        // ページがフレームでアクティブになったら呼び出される
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            camera = new PhotoCamera();
            camera.Initialized += camera_Initialized;
            PreviewBrush.SetSource(camera);
        }

カメラの起動と初期化処理が完了すると、camera_Initializedメソッドが実行されます。カメラは大抵横向きに付いていますのでカメラの回転角度に合わせてプレビュー表示を回転させます。

        // カメラの初期化処理の完了
        void  camera_Initialized(object sender, CameraOperationCompletedEventArgs e) {
            // 初期化処理に失敗した場合は何もしない
            if (!e.Succeeded)
                return;

            // カメラの回転角度に合わせてプレビュー表示も回転させる
            Dispatcher.BeginInvoke(() => {
                PreviewBrush.RelativeTransform = new CompositeTransform() {
                    CenterX = 0.5, CenterY = 0.5,
                    Rotation = camera.Orientation
                };
            });
        }

カメラのプレビュー表示の仕組みはカメラデバイスのレンズから取り込んだ映像をパラパラ漫画のように表示させて、人間の目から見ると滞りなく動いているように見せているアレです。パラパラ映像を切り替える速度の単位をfps(frame per second)といいます。要は1秒間に何枚の画像を表示出来るの?という単位です。

リアルタイムといっても、Windows Phoneに搭載されているカメラの入力フレームレートは約30fps。1秒間に30枚の映像を処理しています。1枚辺り33ミリ秒です。この速度でバーコードの解析は難しいので、1秒間に2回解析を行うようにタイマーを定義します。

        // プレビューフレームの解析を行うタイマー
        DispatcherTimer readTimer = null;

        // カメラの初期化処理の完了
        void  camera_Initialized(object sender, CameraOperationCompletedEventArgs e) {
            // 初期化処理に失敗した場合は何もしない
            if (!e.Succeeded)
                return;

            // カメラの回転角度に合わせてプレビュー表示も回転させる
            Dispatcher.BeginInvoke(() => {
                PreviewBrush.RelativeTransform = new CompositeTransform() {
                    CenterX = 0.5, CenterY = 0.5,
                    Rotation = camera.Orientation
                };
            });
        }

これでカメラ起動は完了です。あとはリアルタイムでプレビューフレームの取り込みを行います。PhotoCamera.GetPreviewBufferArgb32メソッドで、ARGB32フォーマットでプレビュー中に表示されている画像(プレビューフレーム)を取得します。

読み取った結果は、こんな感じになります(画質が悪くて申し訳ない……)。

f:id:ch3cooh393:20140818122508j:plain

ライブラリから直接CameraCaptureTaskを起動する事も出来るらしいのですが、うちの環境では上手く動いてくれなかったのでこのような実装になりました。またライブラリ自体もBeta版ですのでそのうち動くようになると思います。

関連記事

参照

Windows Phoneでアセンブリのバージョンを取得する

Reflectionを使って現在実行中のアセンブリの名前を取得します。

アセンブリの名前からSystem.Reflection.AssemblyNameオブジェクトを生成し、VersionプロパティからSystem.Version型のバージョン情報を取得します。

// アセンブリ名を取得
var nameHelper = new System.Reflection.AssemblyName(
    System.Reflection.Assembly.GetExecutingAssembly().FullName);
// バージョンを取得
var version = nameHelper.Version;

「major.minor」の形式でバージョンを取得する

System.Version型には、Majorプロパティ、Minorプロパティをstringで取得することが出来ますので、string.Formatメソッドでフォーマットします。

// アセンブリ名を取得
var nameHelper = new System.Reflection.AssemblyName(
    System.Reflection.Assembly.GetExecutingAssembly().FullName);
// バージョンを取得
var version = nameHelper.Version;
            
// {major}.{minor}の形式にフォーマットする
var verStr = string.Format("{0}.{1}", version.Major, version.Minor);

Windows PhoneでVibrateControllerクラスを使ってバイブレーションを制御する

Windows PhoneではVibrateControllerクラスを使ってバイブレーターを制御することができます。

バイブレートを開始する

// 700ミリ秒後にバイブレーションを開始する
VibrateController.Default.Start(TimeSpan.FromMilliseconds(700));

バイブレートを終了する

// バイブレーションを停止する
VibrateController.Default.Stop);

参照

Windows PhoneでGeoCoordinateWatcher(GPS/位置情報測位)クラスを使って位置情報を取得する

概要

Windows Phone Location Serviceへアクセスする手段を提供してます。

Windows Phone 7.5("Mango"アップデート)からはWindows Phone エミュレータの標準機能としてGPSシミュレータが付きますが、それ以前の開発環境では「GPSをエミュレートする」を参考にして頂きながら、PC上での試験をおこなうようにするとテストがスムーズかもしれません。

名前空間:System.Device.Location

  • System.Object
    • System.Device.Location.GeoCoordinateWatcher

Tips

位置情報を取得する

取得したロケーションサービス(位置情報を扱う仕組み)のデータを、以下の様なUIで表示させてみましょう。一番上からロケーションサービスのステータス、緯度(latitude)、経度(longitude)の値を表示させています。

f:id:ch3cooh393:20141113133712p:plain

System.Device.Location名前空間のクラスを使用して位置情報を取得します。参照の追加ダイアログにて「System.Device」を参照しておきます。更にusingディレクティブに追加しておきましょう。

using System.Device.Location; // for Location Service
using System.Windows;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;

GPSデバイスから取得した位置情報をアプリケーションで受け取るにGeoCoordinateWatcherクラスを使用します。

下記のサンプルコードではページ遷移後にOnNavigatedToメソッドが実行され、GeoCoordinateWatcherインスタンスの生成をおこない、位置情報の取得を開始します。

物理的なセンサーデバイスからの入力を受け取るため、位置情報を取得するのは殆どのケースでは1秒未満に位置情報が取得できますが、取得が遅い場合1分掛かることも有り得ます。

高精度で位置情報を取得したい場合はコンストラクタ引数にGeoPositionAccuracy.Highを指定しています。精度は低くても測定速度を上げたい場合はGeoPositionAccuracy.Defaultを指定します。

namespace GeoCoordinateWatcherTest {
    public partial class MainPage : PhoneApplicationPage {
        // コンストラクター
        public MainPage() {
            InitializeComponent();
        }

        GeoCoordinateWatcher watcher;

        // ページ遷移されてきた時に呼び出される
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            
            // GeoCoordinateWatcherのインスタンスを生成する
            // Highを指定すると高精度で位置測定する
            watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
            // 精度よりも測定速度を優先する場合はDefaultを指定する
            //watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);

            // 位置が変更されたことを判定する最短距離(単位:メートル)
            watcher.MovementThreshold = 20;

            // 位置が変更された時に発生するイベントハンドラを追加
            watcher.PositionChanged += watcher_PositionChanged;

            // ロケーションサービスの状態変化時に発生するイベントハンドラを追加
            watcher.StatusChanged += watcher_StatusChanged;

            // データの取得を開始する
            watcher.Start();
        }

以上で位置情報の取得を開始します。ロケーションサービスのステータス変更イベント、位置が変更したイベントの取得の仕方について後述します。

ロケーションサービスの状態が変化された時のイベント

ロケーションサービスの状態が変化するとStatusChangedイベントが発生します。ここではイベントハンドラで状態を受け取り、TextBlockコントロールに日本語で説明を表示させています。

TextBlockの値を変更するにはUIスレッドからおこなう必要があります。ただ、GeoCoordinateWatcherからのイベントは別のスレッドから返ってくる為、BeginInvokeメソッドを使ってUIスレッド上で非同期に実行しています。

// 状態が変更された場合に呼ばれるイベントハンドラ
void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) {
    
    // TextBlockの値を変更したいのでUIスレッド上で実行させる
    Deployment.Current.Dispatcher.BeginInvoke(() => {

        // ステータスの内容によって表示する文言を変更する
        switch (e.Status) {
            case GeoPositionStatus.Initializing:
                labelStatus.Text = "初期化中";
                break;
            case GeoPositionStatus.Ready:
                labelStatus.Text = "動作中";
                break;
            case GeoPositionStatus.NoData:
                labelStatus.Text = "動作中だが、位置情報が取得できていない";
                break;
            case GeoPositionStatus.Disabled:
                labelStatus.Text = "非サポートか無効にされています";
                break;
        }
    });
}

移動して位置情報が変更された時のイベント

前回測位した位置より移動し、MovementThresholdプロパティに設定した最短距離以上移動した場合にPositionChangedイベントが発生します。ここではイベントハンドラで位置情報を受け取り、TextBlockコントロールに整形された値を表示しています。

こちらのイベントも別スレッドで通知される為、BeginInvokeメソッドを使用しています。

// 位置情報が変更された場合に呼ばれるイベントハンドラ
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) {

    // TextBlockの値を変更したいのでUIスレッド上で実行させる
    Deployment.Current.Dispatcher.BeginInvoke(() => {
        
        double latitude = e.Position.Location.Latitude;
        double longitude = e.Position.Location.Longitude;

        labelLatitude.Text = string.Format("{0:0.0000}", latitude);
        labelLongitude.Text = string.Format("{0:0.0000}", longitude);
    });
}

参照

関連記事

Windows PhoneでWebBrowserコントロールで指定したページへ遷移する

WebBrowserコントロールにて、「http://ch3cooh.jp/」など指定したページを見たい場合、SourceプロパティにUriオブジェクトを設定します。またプログラム上では、Navigateメソッドを使ってページ遷移を行うことも出来ます。

XAMLで指定する方法

XAMLだけで完結させる場合は、以下のように書くことが出来ます。SourceプロパティにURLを指定しています。ここでは静的な文字列を指定していますが、データバインディングさせることももちろん可能です。

    <phone:WebBrowser Name="webBrowser1" Source="http://ch3cooh.jp/" />

プログラム上で指定する方法

プログラム上で指定する場合についてもご紹介します。XAML側でWebBrowserコントロールを配置しておきます。ここではSourceプロパティを指定していないのに注目してください。

    <phone:WebBrowser Name="webBrowser1" />

Uriオブジェクトを生成し、Sourceプロパティに対して設定します。これでページ遷移が行われます。

  webBrowser1.Source = new Uri("http://ch3cooh.jp/");

もしくは、Navigateメソッドを使用する方法もあります。以下のように指定することで、ページ遷移を行います。

  webBrowser1.Navigate(new Uri("http://ch3cooh.jp/"));

参照

TiltEffectを使ってボタンやコントロールが押された時にエフェクトをつける

Windows Phone 7は静電容量式のタッチパネルを採用しています。静電容量式のタッチパネルはハードウェアボタンと違い、例えばボタンを押していてもユーザーは押している感覚がありません。

HTCの端末ではBackキーや検索キーを押下した時にはバイブされます。Silverlight for Windows Phone ToolkitのTiltEffectを使ってユーザーへタップした感覚をエフェクトを使ってフィードバックします。

参照