月別アーカイブ: 2014年8月

WinRTで画面遷移の履歴スタックを削除する

WindowsRuntime(WinRT)アプリで画面遷移を行っている際に、一気にTOPページに戻したいけど、戻した後に戻ってこられては困るという時があります。

そこで下記のコードを「OnNavigatedTo/NavigationHelper_LoadState」に書いておきます。

Frame.BackStack.Clear();

このAPIで履歴スタックを一括で消せます。

また、あるページに到達した時点で、直前のページには戻したくなく、入力などを行ってるページまで戻したい場合などに、戻す件数を把握してBackKeyが押された際の制御を行うのもアプリの構成としてはありだと思います。

下記のように「Frame.BackStack.RemoveAt」を利用して指定したスタックを削除することもできるので、使い分けるといいでしょう。

            // 画面遷移の履歴スタック数を取得する
            int stackCount = Frame.BackStackDepth;
            for (int i = 0; i < stackCount; i++)
            {
                // 指定した位置のBackコレクションを削除
                Frame.BackStack.RemoveAt(0);
            }

WindowsRuntime8.1/WindowsPhoneSilverLight8.1での日本語フォントが中華フォントになることの回避方法

さて、以前からWindowsPhoneアプリの開発で日本語フォントが中華フォントに置き換えられることがあり、これを回避する方法のコードがテンプレートにも取り込まれていたのですが、WindowsPhone8.1から消えていました。

現在私は「universal Apps」を優先的に行っているので、環境としては「WindowsRuntime 8.1」での開発となっています。

そこで、これまで通り下記コードを書いていたのですが、これが返す値がアプリに設定された言語を返すようになっています。
「en」のみで作成している場合、以前は実行環境の「ja」が返ってきたのですが、「en」が返ってくるようになっています。

                rootFrame = new Frame();

                rootFrame.Language = System.Globalization.CultureInfo.CurrentUICulture.Name;

Twitter上で話題が出た際にBluewaterSoftの山本氏が、その原因となった変更と新しく使用するとよいAPI「GlobalizationPreferences」を見つけていただけました。
そのAPIを利用するのが下記のコードです。
続きを読む

dynabook TabをWindowsストアアプリのリモートデバッガで使用する

2014/05/29-30に行われた日本マイクロソフト社主催のイベント「de:code」で学習用機材として配布された「TOSHIBA dinabook Tab VT484/22K」を活用する一歩として、Windowsストアアプリのリモートデバッグを出来るようにしてみました。

使用した機材
・母艦PC:デスクトップPC
・タブレット:TOSHIBA dinabook Tab VT484/22K
・LAN:BUFFALO 10/100M USB2.0用 LANアダプタ LUA3-U2-ATX
・USB変換:ELECOM タブレットPC用USB変換アダプタ A(メス)-microB(オス) TB-MAEMCB010BK

リモートデバッグを行う場合は同一ネットワーク内にある必要があります。
その為デスクトップPCと接続するため、有線LANにするためUSB-LANアダプタを使用しました。

設定
・ルーターのDHCPでMACアドレスを利用してIPを固定しています。
固定していなくても実行可能とは思いますが、IPがコロコロ変わるのは面倒なので、固定しました。

必要なソフト
・母艦PC側はVisualStudio2013(Update3適応済み)を使用しています。
・dynabook Tabには「Remote Tools for Visual Studio 2013 Update1 x86」をインストールします

「Remote Tools for Visual Studio 2013」は「x86」「x64」「ARM」があります。
dynabook Tabでは「x86」版を使用しています。
dynabook Tab以外で行う場合は其々環境にあったバージョンをご使用ください。

インストール後、「Remote Debugger」を起動します。
起動すると各種設定に関する承諾が出ますがOKを押してください。
「Visual Studio リモート デバッグ モニター」が表示され、「サーバが開始され、接続を待っています」と表示されれば、「dynabook Tab」側は準備完了です。

Remote
母艦PC側のアプリソリューションを開き、アプリ動作先を「リモートコンピュータ」に変更して実行します。
実行の際、dynabook Tabがロックされていないように注意してください。
ロックされていると転送エラーになり、作業できません。

実行すると「接続先の選択」が表示されますので、きちんと接続準備ができていれば、リモートの「dynabook Tab」が選択可能です。(使用している開発言語で違いがあります)

接続が完了すると「開発者ライセンス認証」が促されます。
認証を行うとアプリが転送され、リモートデバッグが可能になります。

マルチタッチやカメラ、比較的非力なタブレット型でのデバッグが可能になり、開発のアイデアも浮かびやすいのではないかと思います。

Windowsデベロッパーセンターに「リモート マシンでの Visual Studio からの Windows ストア アプリの実行」という項目があり、ここに詳細がかかれています。

WindowsPhone8.1でカメラ操作(MediaCapture)

WindowsPhone8.1でカメラ操作(MediaCapture)と銘打ちましたが、普通にMediaCaptureを使用したサンプルなどは良くあります。
にもかかわらず、なぜに?となりますが、よくサンプルが出ているのは「WindowsRuntime」ベースのMediaCaptureです。
そこで「WindowsPhone SilverLight 8.1(以下WPSL8.1)」ベースでの解説など行うことにしました。

なぜWPSLで「MediaCapture」なのかですが、「PhotoCaptureDevice」API群がWindowsPhone8.1では非推奨(VS上では使用不可と出る)なためです。

さて、大きな違いですが、WPSL8.1ではUIElementの「CaptureElement」が存在しません。

WPSL8.1では今までの方法同様「VideoBrush」にアタッチする形をとります。
その為のAPIとして「Windows.Phone.Media.Capture.MediaCapturePreviewSink」があります。

			<Rectangle x:Name="PreviewRectangle" Width="450" Height="450" VerticalAlignment="Top" Margin="0,40,0,12" Tap="PreviewRectangle_Tap" >
				<Rectangle.Fill>
					<VideoBrush x:Name="PreviewBrush">
						<VideoBrush.RelativeTransform>
							<CompositeTransform x:Name="previewTransform" CenterX=".5" CenterY=".5" Rotation="90" />
						</VideoBrush.RelativeTransform>
					</VideoBrush>
				</Rectangle.Fill>
			</Rectangle>

定番の方法で「Rectangle」に「VideoBrush」を設定します。
「Rotation=”90″」は入力が90度回転した状態で送られてくるためです。

次にコードの部分です。
基本構成としては「初期化」「プレビューの開始」「プレビューの停止」「解放」となっています。
また、基本以外のところでは「フォーカス」「カメラIDの取得」を行っています。

    public class CameraDevice : IDisposable
    {
        // キャプチャー本体
        private MediaCapture _captureManager;
        // プレビュー用
        private MediaCapturePreviewSink _previewSink;
        // プレビュー判定
        private bool _bPreview = false;

        /// <summary>
        /// Camera Device Initialize
        /// </summary>
        /// <returns></returns>
        public async Task CameraDeviceInitialize()
        {
            try
            {
                // Get DeviceID rear camera
                var devId = await GetCameraId(Panel.Back);

                // 初期化
                _captureManager = new MediaCapture();

                await _captureManager.InitializeAsync(new MediaCaptureInitializationSettings
                {
                    StreamingCaptureMode = StreamingCaptureMode.Video,
                    PhotoCaptureSource = PhotoCaptureSource.Photo,
                    VideoDeviceId = devId.Id
                });

            }
            catch (Exception ex)
            {
                throw new Exception("CameraDeviceInitialize : " + ex.Message);
            }
        }

        /// <summary>
        /// Start PreView
        /// </summary>
        /// <param name="capturePreview">Preview area VideoBrush</param>
        /// <returns></returns>
        public async Task StartPreView(VideoBrush capturePreview)
        {
            try
            {
                if (_captureManager != null)
                {
                    // Preview Sink Initialize
                    _previewSink = new MediaCapturePreviewSink();

                    // Photo Primary
                    _captureManager.VideoDeviceController.PrimaryUse = CaptureUse.Photo;

                    // List of supported video preview formats to be used by the default preview format selector.
                    var supportedVideoFormats = new List<string> { "nv12", "rgb32" };

                    // Find the supported preview format
                    var availableMediaStreamProperties =
                        _captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(
                            Windows.Media.Capture.MediaStreamType.VideoPreview)
                            .OfType<Windows.Media.MediaProperties.VideoEncodingProperties>()
                            .Where(p => p != null
                                        && !String.IsNullOrEmpty(p.Subtype)
                                        && supportedVideoFormats.Contains(p.Subtype.ToLower()))
                            .ToList();

                    var previewFormat = availableMediaStreamProperties.FirstOrDefault();

                    // Start Preview stream
                    await
                        _captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(
                            Windows.Media.Capture.MediaStreamType.VideoPreview, previewFormat);

                    await
                        _captureManager.StartPreviewToCustomSinkAsync(
                            new Windows.Media.MediaProperties.MediaEncodingProfile { Video = previewFormat }, _previewSink);

                    // Set the source of the VideoBrush used for your preview
                    Microsoft.Devices.CameraVideoBrushExtensions.SetSource(capturePreview, _previewSink);

                    _bPreview = true;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("StartPreView : " + ex.Message);
            }
        }

        /// <summary>
        /// Stop Preview
        /// </summary>
        /// <returns></returns>
        public async Task StopPreView()
        {
            try
            {
                if (_captureManager != null && _bPreview)
                {
                    await _captureManager.StopPreviewAsync();

                    _bPreview = false;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("StopPreView" + ex.Message);
            }
        }

        /// <summary>
        /// I explicitly free
        /// </summary>
        public async void Dispose()
        {
            if (_captureManager != null)
            {
                await StopPreView();
                _captureManager.Dispose();
            }
        }

        /// <summary>
        /// I will confirm the presence or absence rear camera, front camera
        /// </summary>
        /// <param name="desired"></param>
        /// <returns></returns>
        private static async Task<DeviceInformation> GetCameraId(Panel desired)
        {
            //var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

            DeviceInformation deviceId = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
                .FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desired);

            if (deviceId != null)
            {
                return deviceId;
            }
            else
            {
                throw new Exception(string.Format("Camera of type {0} doesn't exist.", desired));
            }
        }

        /// <summary>
        /// Execution of focus
        /// </summary>
        /// <returns></returns>
        public async Task SetFocusTask()
        {
            try
            {
                if (_captureManager == null)
                {
                    return;
                }

                foreach (var variable in _captureManager.VideoDeviceController.FocusControl.SupportedFocusModes)
                {
                    Debug.WriteLine(variable.ToString());
                }

                if (_captureManager.VideoDeviceController.FocusControl.Supported)
                {
                    _captureManager.VideoDeviceController.FocusControl.Configure(new FocusSettings { Mode = FocusMode.Auto, DisableDriverFallback = true });

                    await _captureManager.VideoDeviceController.FocusControl.FocusAsync();

                    Debug.WriteLine("focus supported");
                }
                else
                {
                    Debug.WriteLine("focus Not supported");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("SetFocusTask" + ex.Message);
            }
        }
    }

使用の際は「CameraDeviceInitialize」行って「StartPreView(PreviewBrush)」すると開始されます。
「PreviewBrush」が表示されていない場合は例外が発生しますので注意してください。

「OnNavigatingFrom」でプレビューの停止と解放を行いましょう。
「OnNavigatedTo」に初期化を書いておくことで、復帰の際にも対処可能です。

フォーカスやその他の機能に関しては必ずサポートの有無を確認したうえで、操作を開始しないと未サポートの場合、例外が起きて停止します。

駆け足ではありますが、これでWPSL8.1環境下でもカメラが使用可能です。

ただ使用して思うのは、このAPIでは機能が制限される端末が存在しうることです。
「Lumia 1320」ではフォーカスが可能なのですが「Samsung ATIV S」では未サポートとなります。(旧APIでは使用可能)
これは、使用しているWindowsPhone8.1がDeveloperPreviewであることが原因の可能性もあります。

それでも、明らかに以前より機能が落ちるAPIを使用しなければいけないのは残念です。(「入力画素数」が指定できない等)
もっとも、自分がまだAPIを把握し切れていないために、使いきれていないということもあり得ます。

今後WPSL8.1はOSのバージョンアップなどに伴って、使用可能なAPIが制限されるのではないかと思いますので、アプリを作成する際は、ストアへの登録のしやすさなども考え見ると「universal Apps」を前提として「WindowsRuntime」ベースへ移行していったほうがよいと思います。

もっとも、WinRTでは使用できないAPIが多くあるのも事実ですので、そういったAPIを生かしたアプリを作るのであれば「WindowsPhone SilverLight 8.1」ベースで作りこむのがよいと思います。