カテゴリー別アーカイブ: WinRT

Syncfusion Essential Studio に COMMUNITY LICENSE が!

Syncfusion 社の「ESSENTIAL STUDIO」に≪COMMUNITY LICENSE≫が追加されました!

ESSENTIAL STUDIOって?

ESSENTIAL STUDIOはアプリを開発する際に使用可能なコンポーネントライブラリです。
android、iOS、Xamarin(Android,iOS,Forms)、JavaScript、ASP.NET、ASP.NET MVC、Windows Forms、WPF、WinRT、UWP、Windows Phoneの各種プラットフォームに対応しています。

何ができるの?

自作しようとすると面倒になりがちな「チャート」や「カレンダー」、「ダイアグラム」、「PDF」などをコンポーネント提供してくれています。

COMMUNITY LICENSEって結局なに?

・個人開発者
・年間売り上げ100万$(約1億円)以下の企業
・使用可能な開発ユーザー5人まで
上記の条件を満たしていれば「無償」で使用可能なライセンスになっています!
しかも、「商用アプリも可」というすごいライセンスです。

なんでそんなすごいライセンスが提供されたの?

マイクロソフト社が「Visual Studio Community」という開発ソフトの無償ライセンスの拡充を行ったことに触発されて、Syncfusion 社が提供に踏み切ったそうです。

使うにはどうするの?

COMMUNITY LICENSEのページ≫からユーザー登録をしてダウンロード後、インストールしてください。
専用のアンロックキーが提供されますので、キーの入力で使用可能になります。

さて、さらにありがたいことにSyncfusion 社は≪METRO STUDIO≫というフリーのアイコンツールも提供していただけています。
アプリの作成時に必要な各種アイコンはこれでほぼ事足りますので、ぜひ一緒に使用しましょう。

そして最後にVisual StudioXamarinを利用して、ぜひアプリを作りませんか?

マウスコンピューターからWindowsPhoneベース端末開発表明が

WindowsPhoneベース端末が日本企業から出るかもしれない

マウスコンピュータのニュースリリースに、日本のWPアプリ開発者待望といってもいいものが掲載されました。
マウスコンピューター、Windows Phone ベースのデバイス開発契約を締結し、開発着手のお知らせ

もちろん、パナソニックの「FZ-E1」というWindowsPhoneベース端末がありますが、ニュースリリースからLTEのSIMフリー機になる予定となっていることから期待は大きいです。

もちろんこれは開発契約を締結したというニュースリリースなので、今後はまだ不明な点は多いです。

OSのバージョンは?

時期的に「WindowsPhone 8.1」なのか「Windows 10 for Phones」になるのかワクワクしますが、「Windows Embedded 8.1 Handheld」もWindowsPhoneベース端末なんですよ、、、

しかし、日本企業から日本で開発表明がされたことは非常にうれしい出来事です。

期待しながら続報を待つことにします。

Windows 10 for mobile ?

Windows10でさらに統合が進むのか?

今月21日(PST)、日本では22日深夜ですが、Windows10に関するMicrosoft社のイベントが開催されるそうです。
そうなると注目したのはWindowsPhoneに関する情報がということになるのですが、タイトルに書いていますが「Windows 10 for mobile」とOS名は変わる可能性があるようです。

自分は、WindowsPhoneという名称はそのまま使われるんではないかと予想はしています、変わるのはOS名称だけかなと。

さて、Windows10は「Windows Insider Program」というテストプログラムが用意され、一般ユーザーもテスト環境を構築して、Microsoftへの要望などを行えるようになっています。
このプログラムのWindowsPhone版ともいうべきプログラムが開始されるようで、WindowsPhoneストアに「Phone Insider」という公式アプリが公開されました。

現在はロックがかかっているようなので、インストールしても使用はできません。

a17456e7-8840-49e9-baad-d621b08b96c1

be4186ca-e744-454e-8711-4350bcca16e0

c610d20d-1206-4956-8fb0-16377a67de73

WindowsPhone 10?って?

Windowsとの統合がさらに進むということは伝えられていますが、統合が進むのは「WinRT API」で、WindowsストアアプリのAPIの共通化が進むようです。
もちろん、Phone(電話)向けのAPIがさらに進化する、または整頓されて使いやすくなっていくのではないでしょうか?

Windows8/8.1で搭載されたWindowsストアアプリとの互換性が上がり、WindowsPhoneアプリとの統合が進み、ほぼワンソース(現在もかなり近い状態ですが)でアプリストアも一か所にまとめられるのではないかといわれています。

勘違いしてほしくはないのですが、Windowsのデスクトップで使用する通常のWindowsアプリがPhoneで使えるわけではないです。
MacのアプリがiPhoneで使えないのと一緒ですね。

さて、この発表で日本でのWindowsPhoneに関することは出なさそうな気はしていますが、新しいOS、開発環境に関しては開発者としてワクワクしますね。

どのような発表が行われるか、楽しみです。

WindowsPhone8/8.1 Game Pad/Controller

WindowsPhone8/8.1(以降WP8/8.1)にはGame Pad/Controllerが有りませんでした。
これはモバイル向けGame Pad/Controllerとの接続で良く使用されるBluetoothですが、WP8/8.1にはBluetoothは搭載されているものの、対応profileとして「HID」が無いため外部入力機器が使用できませんでした。

ところが、最近検索していて見つけたのですが、Bensussen Deutsch & Associates, Inc(以下 BDA)社の「MOGA Game On Anywhere(以下 MOGA)」シリーズの一部が対応しているとの記事を見つけました。

MOGAにはiPhone用とAndroid用のゲームコントローラーがあるのですが、Android用でWP8/8.1に使用できる機能が付き、WP8用SDK(WinPRT)が公開されています。

MOGA Pro SDK – WindowsPhone8

自分は下記のコントローラーを購入して、SDKにあったサンプルでコントローラーが動作することを確認しました。


此方はUSB充電伝可能なリチウム電池内蔵型です。


価格は安いものの、単三電池二本が必要になる、リチウム電池やUSBコネクタはありません。

というわけで、WP8(WinPRT)用とはなっているものの、WP8.1WinRTベースで使用できるようにできないかと、色々試してみました。

続きを読む

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を利用するのが下記のコードです。
続きを読む

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」ベースで作りこむのがよいと思います。

WindowsPhoneでダイスと籤

アプリを作っていると、いろいろな判定やランダムによるチェックを行うことがあると思います。

その中でもよくある方法としては、ダイス(サイコロ)を振ってその数値による判定というのと、一定数の当たりから籤を引くという判定があります。

まずはダイス判定関数です。
基本はランダムを利用したもので、ランダム用のシードを作成する関数。
シード利用してランダム関数をコールして、結果の数値に+1して返すダイス関数。(Random.Next(Count)は0~指定数値-1なので)
複数ダイスを判定する関数で構成しています。

        /// <summary>
        /// 複数ダイスのロール
        /// 2D6 なら DiceRoll(2, 6)
        /// 1Dなら「.First<int>()」をつけて呼び出せばintで見れる
        /// </summary>
        /// <param name="numCount">サイコロの数</param>
        /// <param name="surfaceCount">サイコロの面数</param>
        /// <returns>各個の返り値</returns>
        public static int[] DiceRoll(int numCount, int surfaceCount)
        {
            var ret = new int[numCount];

            for (int i = 0; i < numCount; i++)
            {
                ret[i] = Dice(surfaceCount);
            }

            return ret;
        }

        /// <summary>
        /// サイコロ
        /// 数値は0~maxCount - 1なので、出てきた数値に + 1
        /// </summary>
        /// <param name="maxCount">最大数を渡す、D6なら6を</param>
        /// <returns>1~maxCount</returns>
        private static int Dice(int maxCount)
        {
            // シードを生成
            var rnd = new Random((int)GenerateRndNumber());

            var ret = rnd.Next(maxCount) + 1;

            return ret;
        }

        /// <summary>
        /// ランダム用のシード生成
        /// </summary>
        /// <returns></returns>
        private static UInt32 GenerateRndNumber()
        {
            // Generate a random number.
            var rnd = CryptographicBuffer.GenerateRandomNumber();

            return rnd;
        }

次に、籤による判定関数です。
この関数は、箱の中に当たりくじを入れて、その配列を返す関数にしています。
普通にダイス関数での判定でもいいではないかと思う方もいらっしゃると思いますが、これは当たり籤を判断させるための判定です。

どこかに入っている当たりくじを引くというのはダイスでは比率になり、ランダム性にかけます。

そこで、当たりくじの箱を作って、ダイスを振り、そこが当たりくじかどうかを判定することで、比率だけではない判定を行うために作製しました。

        /// <summary>
        /// 100の中に当たりくじをランダムで仕込む
        /// </summary>
        /// <param name="trueDataCount">あたりの数</param>
        /// <returns></returns>
        public static bool[] CreateHundredLottery(int trueDataCount)
        {
            if (trueDataCount > 100) return null;

            // falseで初期化
            bool[] bLotteryArray = Enumerable.Repeat<bool>(false, 100).ToArray();
            bool[] bAddArray = Enumerable.Repeat<bool>(true, trueDataCount).ToArray();

            bAddArray.CopyTo(bLotteryArray, 0);

            // 配列のランダム化
            var retArray = bLotteryArray.OrderBy(i => Guid.NewGuid()).ToArray();

            // 配列の中身を確認する
            // string stData = string.Join(Environment.NewLine, retArray);
            // Debug.WriteLine(stCsvData);

            return retArray;
        }

これらのコードはWindowsPhoneSilverlight8.1ベースですが、WinRTでもほぼそのまま使えるのではないかと思います。
書き換えるとしたらシード生成のところを書き換える形で、Windowsストアアプリでも使用は可能なはずです。

WindowsPhone8.1開発メモ

WindowsPhoneのデバッグ作業の際、実機とエミュレータで試しますが、機能によってはエミュレータではカメラなどはできません。
(WebCamと連携してカメラが使えるとかになってほしい気はしてます)

そこで実機で動作中なのか、エミュレータで動作中なのかでコード分岐をしたいと思う時があります。

その為の判断は「if(Environment.DeviceType == DeviceType.Emulator)」でエミュレータであることを確認できます。

Environmentは「Environment.NewLine」等、改行コードを追加などで使われることが多いと思いますが、現在のところWindowsPhoneSilverlightでは「DeviceType」のみの実装となります。

WindowsPhoneWindowsRuntimeでは、「Environment.NewLine」が使用可能ではありますが「Environment.DeviceType」がありません。

これは、WindowsPhoneSilverlightでは「Microsoft.Devices.Environment」でWindowsPhoneWindowsRuntimeでは「System.Environment」で判定されるためです。

WindowsPhoneSilverlight開発では明示的に「System.Environment」とすれば、「System.Environment.NewLine」なども使用可能ですが、WindowsPhoneWindowsRuntime開発の場合はWindowsPhoneSilverlightを呼び出せないため、「Microsoft.Devices.Environment.DeviceType」は使用できません。

こんな所にも違いがあるので注意が必要です。

ViewBox下でManipulationを行う場合

Viewbox>Canvas>UIElement
画面サイズに左右されないように、上記のような構成で行っているの場合が多いと思います。
この時にManipulationを使用してUIElementを移動させる場合、ずれが出ます。
Viewboxがサイズだけでなく移動距離も変換しているためとみられます。

これを解決する方法としては、Viewboxの変換スケールを取得して、移動量をスケールで除算することで可能です。

private void ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
{
        var scaleX = Viewbox.ActualWidth / Viewbox.Child.DesiredSize.Width;
        var scaleY = Viewbox.ActualHeight / Viewbox.Child.DesiredSize.Height;

        double x = e.Delta.Translation.X;
        double y = e.Delta.Translation.Y;

        x = Canvas.GetLeft(obj) + (x / scaleX);
        y = Canvas.GetTop(obj) + (y / scaleY);
}

0除算チェックなどはしてないコードですが、こんなのでどうにかなります。

個人的には、移動までスケール変換されるのはどうなのかなとは思いますが、仕様ということならしょうがない(;´Д`)

でも、これはこれで修正されるとこのコード入れてるのがおかしくなるだろうから痛し痒し、がらっとバージョン変わった時でないと分離できないかなー