ラベル UWP の投稿を表示しています。 すべての投稿を表示
ラベル UWP の投稿を表示しています。 すべての投稿を表示

2019年11月20日水曜日

UWPアプリのサイドローディングする方法

他のパソコンで作成したUWPアプリをPowerShellを使ってインストールしようとするとセキュリティポリシーエラーが発生するのを回避する方法。

PowerShellを管理者権限で実行する。

Set-ExecutionPolicy RemoteSigned

を実行する。

これで解決。

2019年10月4日金曜日

【UWP】UWPアプリーWebView間でデータの受け渡しする方法


いよいよ.Net core3.0が正式リリースされました。

その中で一番気になる技術はやはりクロスプラットフォーム化に進んでいるというところです。

今までクロスプラットフォーム化でネックになっているのがGUI画面とハード依存周り。

Gnome、KDE、Win、Mac、・・・様々なGUIが異なる実装をしているから画面回りを1つにまとめられない。。

Windows/Mac/Linux・・・と足回りも異なるOSだからUSBドライバ1つとっても実装を分けないといけない。。

考え出すと切りがないのが現状だったりします。

そこを打破すべくMSが推し進めているのが.Net coreプラットフォーム。

こいつを使えば足回りは1つで統一だぜヒャッハー!ってなるんだけど、
画面回りだけは、
 XAMLの場合はXamarinで統一?
 HTML/JS/CSSの場合はElectron、Blazorで統一?

まだ安定してませんね。
でもXAML to HTML などのコンバーターがいずれ出てくるでしょうが
今回は後者のHTML/JS/CSSを使った場合についてです。

このケースはXAMLでWebViewを張り付けて用意したWebページを表示して
データ操作をしたりしなかったりするんですが、
WebView↔C# の間でデータをやり取りを行う必要があるわけです。

最近のWebフレームワークなAngularやReactなどはWebサーバと通信するんですが
アプリと通信します。

そのインターフェイスに必要になる技術がこちら。

★C#→Javascriptのコードを呼び出す場合
 var data = await web.InvokeScriptAsync("eval", new string[] { "testfunc();" });

★Javascript→C#へ通知する場合
 window.external.notify("foo bar");
 ※C#側:WebviewのScriptNotifyイベントに通知されます。

この2つです。

使うときの注意点は、
受け渡し可能なデータ型は「文字列」のみであること。

早くBlazorのクライアントサイドが正式リリースされないかなー


【参考URL】
https://blogs.msdn.microsoft.com/japan_platform_sdkwindows_sdk_support_team_blog/2013/11/27/webview-10/

2017年9月11日月曜日

[UWP]2017年版UWPアプリを作る時に覚えておくこと

.Net Core 2.0や .Net standard 2.0が登場して間もない時期ですが、
ようやく下位互換になった!
というか
ようやく置いてけぼり感を食らっていたユーザーに光が差し込まれました。

UWPアプリで書くTaskや新しいインターフェイスを書かずとも

今まで通りの感覚でプログラムが書けます!

( ˘ω˘ )

2017年秋から本格的にUWPアプリを書き始めてみようかなと思いました。

まず今までと違うところが1つあって、
無い!って思ったライブラリ関係は
全部Nugetで追加していかないといけません。

その代名詞になるのが、シリアルポートでしょうか。

それにUWPのUIって全部XAMLで書かないといけないのかって
悩ましい問題も実はテンプレート関係が揃ってるライブラリもNugetにあります。

今までモノシックに出来上がったライブラリが
分割できる特殊パーツはNugetにしようって流れですね。

Nugetに何があるか分からないけど 視点を変えて、

無いものはまずWEBでNugetライブラリ検索しよう

という新しいスタイルをもって開発した方がよさそうです。

まずは簡単に必要最小限に必要な知識としては、
プログラムを全部ライブラリ化して、
UI部分をXamarinやWinform、UWPなどいろんなプラットフォームに合わせて作成する感じですね。

ということで、

ライブラリは.Net Standard 2.0で作る
 これ重要。



ついでにプライベートレポジトリを作っておくと便利なので、

Nugetパッケージを作る
・コマンドラインを開き、.slnファイルのある場所でdotnet pack



ハード制御したいよっという場合は、

シリアルポートを使う
・nugetで Ststem.IO.Portsをインストール



UWPアプリってXAMLタグ打つの大変、、ハンバーガーメニューを一発で使いたい場合は

UWPの画面回りテンプレートを使う
・nuggetで Microsoft.Toolkit.Uwpをインストール  
 サンプルがWEBストアにあって、
 UWP Community Toolkit Sample Appをインストール。
 Microsoft.Toolkit、Microsoft.Toolkit.Servicesこの辺りも使えそう。


ひとまずはこれを知っておけとなんとかなりそうです。

2017年5月24日水曜日

[UWP]VS2017でAdControlを用いて広告を挿入するには

はじめに

SDKをインストールするやり方がありましたが、VisualStudio2015までのやり方で
VisualStudio2017ではインストーラでインストールすることができません。
新しいやり方はNugetからインストールになります。




手順


Step1.Nugetから必要なライブラリをインストール

Nugetを開いたら
「Microsoft.Services.Store.SDK」
を検索して追加する。

Step2.参照の追加

参照マネージャーを開き、「Universal Windows」→「拡張」を開き
「Microsoft.Advertising.SDK fot XAML」にチェックを入れてOKボタンを押します。

これで設定完了です。
後は今まで通りに
XAMLを開き、
最初のPageタグの属性に
xmlns:UI="using:Microsoft.Advertising.WinRT.UI"
を追加する。
広告挿入は、

        

のようにする。

もし「クラスが登録されていません」というエラーが出た場合は
ビルドターゲットを[x86]や[x64]など切り替えると解消されるようです。

思った事

ここまで書いて1つ気づいたのが、ようやくAdControl挿入で広告が表示されるようになった事。
今までエラーしか返ってこなかったのでCreators Update以降になって1つ前進した感じがします。
あとは額面でAdmobよりレートの良いものとなってほしいです。
感覚的には今はAdmobの10分の1くらいなんじゃないだろうかってくらいしょぼいです(´・ω・`)


参考URL

https://docs.microsoft.com/ja-jp/windows/uwp/monetize/microsoft-store-services-sdk#a-nameinstall-the-sdkasdk-のインストール



2016年9月13日火曜日

Task async/awaitの挙動チェック AsyncInfo編

Task async/awaitの挙動チェック AsyncInfo編

前回はTaskについて調べた。
今回はUWPアプリで出てくるAsyncInfoについて挙動をチェックする事にした。

前回のTaskをラップしてキャンセルと通知機能を付加する機能なのだが、
スレッドIDはどう割り当てられるのか分からない状態である。
焦点は内包するTask自身がTask.Runするしないの動作、AsTaskした時の動作のチェックである。
AsyncInfoの外側は前回の結果からすると同期処理になっている事からTask.Runしないが正解。
だけどAsyncInfo自身で非同期しているのではないかという疑問があるので調査する事にした。


結果:
 3
 test1=3
 ---
 test2=7
 ---
 test4=7
 ---

・AyncInfo内部で非同期するような処理になっていない(test1)
・AsyncInfoに内包するActionをTask.RunにするとスレッドIDが変わる(test2)
・AsTask().Wait()するとフリーズする(test3)
・AsTask()でスレッドIDが変わらない(test4)

まとめると
・Taskと同じ性質である。
・AsyncInfo内に内包するActionはTask.Runしないこと。



ーーー以下ソースコードーーー


private async void rb2_Click(object sender, RoutedEventArgs e)
{
    Debug.WriteLine(Environment.CurrentManagedThreadId);
    await AsyncInfo.Run(async (token) =>
    {
        await Task.Delay(1);
        Debug.WriteLine($"test1={Environment.CurrentManagedThreadId}");
    });
    Debug.WriteLine("---");
    await AsyncInfo.Run((token) => Task.Run(()=>
    {
        Debug.WriteLine($"test2={Environment.CurrentManagedThreadId}");
    }));
    //freeze
    //Debug.WriteLine("---");
    //AsyncInfo.Run(async (token) =>
    //{
    //    await Task.Delay(1);
    //    Debug.WriteLine($"test3={Environment.CurrentManagedThreadId}");
    //}).AsTask().Wait();
    Debug.WriteLine("---");
    await AsyncInfo.Run(async (token) =>
    {
        await Task.Delay(1);
        Debug.WriteLine($"test3={Environment.CurrentManagedThreadId}");
    }).AsTask();
    Debug.WriteLine("---");
    AsyncInfo.Run((token) => Task.Run(() =>
    {
        Debug.WriteLine($"test4={Environment.CurrentManagedThreadId}");
    })).AsTask().Wait();
    Debug.WriteLine("---");
}



2016年9月7日水曜日

[UWP][C#]非同期処理の処理時間

データを書き込むループを100万回回したときの処理時間。


同期処理 = 1ms
TaskのAsync/Await = 13505ms
TaskのWait() = 7934ms
IAsyncActionのAsync/Await = 14672ms
IAsyncActionのAsTask().Wait() = 26608ms


圧倒的に同期処理は早いです。
API回りで15ms以上掛かる処理にはAsyncな処理になってしまっているのですが、
通信処理って非常に繰り返し実行される部分なので当然処理コストを抑えたいのにTaskを使わないといけないんですよね。。

まぁループのオーダーが100万回なので、
1回当たりの処理コストの単位を[ms]から[ns]に変えてみると良く分かります。

O(1)な同期処理は1ns。当然早いですね。
タスクになると一回のasync/await処理コストの最大で見ると13us~30us
実際にコーディングすると2,3個awaitが発生するので
多くみて100usくらいコストを支払っている事になります。
遅い。。

2016年8月30日火曜日

[UWP]Winアプリストア用のロゴ画像を作成する

Androidよりもたくさん画像を用意しないといけないので、マクロで作成したい所です。
そんな人用に画像スケーリング一覧を作成しました。

サイズ制限もあるので注意しないとダメなんですが、とりあえず3種類に分けて
ロゴ、スプラッシュスクリーン、ワイドロゴの3つ作っておく必要があるようです。
あとはスクリプトで大量生産すれば完了です。


[logo]
1240x1240
620x620
600x600
465x465
388x388
310x310
300x300
284x284
256x256
225x225
200x200
188x188
176x176
150x150
142x142
107x107
100x100
96x96
89x89
88x88
75x75
71x71
66x66
63x63
55x55
50x50
48x48
44x44
36x36
30x30
24x24
16x16


[Splash screen]
2480x1200
1240x600
930x450
775x375
620x300


[wide logo]
1240x600
620x300
310x150
465x225
388x188

2016年8月12日金曜日

[C#][UWP]ViewModelを別スレッドから更新する方法(2)

前回の記事はネット上調べて見つけた方法を利用したやり方だったのだが、
よくよく考えてみると、
 モデルクラス自身が変化を通知する時、
  ・UIスレッド上ならOK
  ・別スレッド上だとNG

という事をどう解決するかでTaskのAsync/Await問題にも波及するわずわらしい問題になっている。

どうやって切り分けたら良いかを考えたら、オブザーバーパターンが有効だという事に気が付いた。

モデルクラスは別スレッドで動いていて、モデルクラスの変化を一定周期で監視するクラスをUIスレッド上で動かしておく。
こうすることでモデルクラスは手を加えずにUIスレッド上で通知する事が可能になる。

色々モデリングして動作チェックして一番シンプルなのがこの方法だったので
同じく困っている人がいたらこの方法を採用してみてください。

---

    public interface IRaisePropertyChanged
    {
        void RaiseNotify(PropertyChangedEventArgs args);
    }

    public class PropertyWatcher
    {
        public PropertyChangedEventArgs args { get; }
        Func getValue { get; }
        object self { get; }
        object value { get; set; }

        public PropertyWatcher(object self, PropertyInfo pinfo)
        {
            this.self = self;
            args = new PropertyChangedEventArgs(pinfo.Name);
            getValue = pinfo.GetValue;
        }

        public bool Check()
        {
            var newValue = getValue(self);
            if (newValue != value)
            {
                value = newValue;
                return true;
            }
            return false;
        }
    }

    public class ModelWatcher
    {
        public IRaisePropertyChanged self { get; }
        public PropertyWatcher[] props { get; }

        public ModelWatcher(IRaisePropertyChanged instance)
        {
            self = instance;
            props = instance
                .GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Select(_ => new PropertyWatcher(instance, _))
                .ToArray();
        }

        public void Polling()
        {
            foreach (var prop in props)
            {
                if (prop.Check())
                {
                    self.RaiseNotify(prop.args);
                }
            }
        }
    }

    public static class ViewModelUpdater
    {
        static CoreDispatcher Dispatcher { get; set; }
        static int uiThreadId { get; set; }
        static DispatcherTimer timer { get; } = new DispatcherTimer();
        static List models { get; } = new List();

        public static void Add(ModelWatcher model)
        {
            lock (models)
            {
                models.Add(model);
            }
        }

        public static void Remove(ModelWatcher model)
        {
            lock (models)
            {
                if (models.Contains(model))
                {
                    models.Remove(model);
                }
            }
        }

        public static void Initialize()
        {
            Dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
            uiThreadId = Environment.CurrentManagedThreadId;
            timer.Interval = TimeSpan.FromMilliseconds(20);
            timer.Tick += (s, e) =>
            {
                lock (models)
                {
                    foreach(var model in models)
                    {
                        model.Polling();
                    }
                }
            };
            timer.Start();
        }

        public static async void UIInvoke(Task action)
        {
            if (uiThreadId == Environment.CurrentManagedThreadId)
            {
                await action;
            }
            else
            {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() => { action.Wait(); }));
            }
        }

        public static async void UIInvoke(Action action)
        {
            if (uiThreadId == Environment.CurrentManagedThreadId)
            {
                action();
            }
            else
            {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(action));
            }
        }
    }



  //テスト用モデルクラス

    public class testmodel : INotifyPropertyChanged, IRaisePropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaiseNotify(PropertyChangedEventArgs args)
        {
            Debug.WriteLine($"Update:{Environment.CurrentManagedThreadId}");
            PropertyChanged?.Invoke(this, args);
        }

        public int value1 { get; set; }
    }

---

使い方

ViewModelUpdater.Initialize();

初期化して

ViewModelUpdater.Add(new ModelWatcher(testmodel));

対象モデルクラスをModelWatcherクラスに渡してViewModelUpdaterに追加する。

監視対象から外す場合はRemoveを使う。








2016年8月10日水曜日

[C#][UWP]ViewModelを別スレッドから更新する方法

ViewModelをINotifyChangedインターフェイス経由で更新しようとすると
PropertyChangedイベントをRaiseした所でエラーになったりフリーズしたりすることがある。
UIに関する事はすべてUIスレッド内で処理しないとエラーになってしまう事など
実装するときのハマりポイントは難なくクリアしたいので、
処理コストを取っても楽するやり方を見つけたのでメモを残しておく。

方法は、UIスレッドに関する部分をUIHelperクラスに記述しておいて
ViewModel内でプロパティ更新するときにUIHelperに更新を依頼するという流れである。


----
    public static class UIHelper
    {
        static CoreDispatcher uiDispatcher;
        static int uiThreadId;
        public static void Initialize(CoreDispatcher uiDispatcher, int uiThreadId)
        {
            UIHelper.uiDispatcher = uiDispatcher;
            UIHelper.uiThreadId = uiThreadId;
        }

        public static bool IsUIThread => uiThreadId == Environment.CurrentManagedThreadId;

        public static async void Dispatch(Action action)
        {
            if (IsUIThread)
            {
                action();
            }
            else
            {
                await uiDispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(action));
            }
        }
    }
----

上記クラスを初期化するInitializeメソッドは
Appクラスの頭あたりで実行しておくのが良い。

UIHelper.Initialize(Dispatcher, Environment.CurrentManagedThreadId);



ViewModelの実装サンプル

----
    public class viewmodel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer.Default.Equals(field, value)) return false;
            field = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            return true;
        }

        int _value1;
        public int value1
        {
            get { return _value1; }
            set { UIHelper.Dispatch(() => { SetField(ref _value1, value); }); }
        }
    }
----

SetFieldの処理の上にActionでくるんでDispatchに放り投げてしまう。
値1つ変更するのになんでこんなコストを払わないといけないんだろうって思ってしまうけど
安定してシンプルになるならコストを払おう。

2016年8月6日土曜日

[UWP]async/awaitでデッドロック(deadlock/freeze)を回避する方法

今までデスクトップアプリを使っていた時は非同期処理は経験則で培った非同期処理を行っていたが、UWP世代になると非同期処理はasync/awaitでやれと言わんばかりにフレームワークの一部として実装されいれるため強要される。

どうやったら上手に向き合って解決していくかノウハウが溜まった所で記事にしておく。

いきなり使い方
 デッドロックをして困った場面など色々書きたい事はありますが、最初からやり方を知っていれば遭遇刷ることは無いのでいきなり使い方から説明します。

・Asyncと付くAPIは最終的にTask.Runで括って実行すること。
 →これがデッドロックの回避策。

・Task.Runは最後の呼び出し以外で使用しないこと。
 →途中で使ってもよいがパフォーマンスが落ちる。

・メソッドで async voidの時はTask.Runで括るは不要。
 →完了を待たない投機的な実行なのでデッドロックしない。

・戻り値がIAsyncActionWithProgressなどとなっているメソッドはその場でAsTaskすること。
 →画面上にくるくる回るウェイト画面を実装したりする場面ではAsTaskしなくてよいが、
  バックグラウンドな処理で一連のシーケンスを同期処理を書きたい場合に有効。

もちろん上記以外の方法でうまく付き合っていける方法があったら、また更新したいと思います。



エラー箇所の調べ方
 ここからはデッドロックにハマって悩んでしまった方用の処方箋。

呼び出すメソッドが
 async Task DosomethingAsync()
  {
    await Task.Delay(1);
  }

となっている場合、
呼び出し側の処理でOK/NGパターンを見るとこうなります。

-----
 void CallerMethod()
 {
   DosomethingAsync().Wait();  //deadlock
 }
-----
async void CallerMethod()
 {
   await DosomethingAsync();  //deadlock
 }
-----
void CallerMethod()
 {
   Task.Run(DosomethingAsync).Wait();  //OK!
 }


-----
async void CallerMethod()
 {
   await Task.Run(DosomethingAsync);  //OK!
 }


-----

ほんとに困ったときはその場でTask.Runで括ってすべて同期処理にして
最後にTask.Runしてタスク分けする方法もありと思います。

UWPで開発する上でどうしても向き合わなければ進まない問題なので、がんばりましょう。

2016年7月27日水曜日

UWP:アプリケーションは、別のスレッドにマーシャリングされたインターフェイスを呼び出しました。 (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

ViewModelにINotifyPropertyChangedインターフェイスを使っていて、用意したTask処理の中でViewModeを更新するとこういったエラーが起きる。

原因は、UIスレッド以外でUIを更新しようとしたからである。
これを対処するにはタスク処理からUIスレッドに処理を実行してもらうことが必要になる。
(データクラスはGet;set;で1行で終わらせられるのを展開して実装しないといけないし、UIスレッドの面倒まで見ないといけないなんてめんどくさいこの上ない。)

この原因を紐解くにはまずTaskの仕組みについて知る必要がある。

~(Task Async Awaitとは)~
 スレッドA(UIスレッド)、スレッドB(別スレッド)の2つあったとしよう。
スレッドAでTaskクラスを実行すると、処理はスレッドBで実行される。
逆にスレッドBでTaskクラスを実行すると、スレッドAになる。
これがTaskクラスで、重たい処理は他スレッドにやらせることが基本動作になる。
Taskクラスの処理が終わりを知るのにawaitを使う。

まとめると、
Task ・・・ 処理の単位
Async ・・・ 別スレッドで動作する処理がある
Await ・・・ 別スレッドからの帰りを待つ

・Taskを作っただけでは別スレッドにはならない。
・タスクをRunさせることでスケジューラに登録されて処理が開始される。


ざっくり書いたがこんな感じに覚えておけば良い。


例でボタンクリックイベントメソッドを使った時の挙動を見てみよう。

OK:そもそも別スレッドでViewModelを更新してないので問題なし

        private void button_Click(object sender, RoutedEventArgs e)
        {
            vm.Update();
        }

NG:ボタンクリックメソッド内のタスク実行したので、別スレッドでUI更新している。

        private async void button_Click(object sender, RoutedEventArgs e)
        {
            await Task.Run(async () =>
            {
                await Task.Delay(1000);
              vm.Update();
            });
        }


OK:ボタンクリックメソッド内でUI更新したので問題なし。
        private async void button_Click(object sender, RoutedEventArgs e)
        {
            await Task.Run(async () =>
            {
                await Task.Delay(1000);
            });
            vm.Update();
        }

OK:2つ上のと違ってUIスレッドで動いているボタンクリックメソッド上でawaitしているので問題なし。

        private async void button_Click(object sender, RoutedEventArgs e)
        {
            await Update();
        }

        async Task Update()
        {
            await Task.Delay(1000);
            vm.Update();
        }


-----

つまり、

・View上のボタンクリックメソッドはタスク処理でないので、UIスレッドで動作しているというのが分かる。
・asyncメソッド内部で複数のTaskが存在していても、それぞれがスケジューラに登録されて実行刷るわけではないので、すべて同スレッドで実行される。
・タスクをRunしたらその時点で別スレッド開始する。

なんとなく分かっただろうか。
少しだけスケジューラについて触れておくと、デバッグ時にタスクウィンドウで現在どのようなタスクが動いているかが見れるようになっていて便利。


最後に別スレッドからUIを更新するには、ViewクラスにCoreDispatcherクラスで定義されたDispatcherプロパティがあるので、これをタスク内にあるUI更新部分を括ると回避する方法を下記にのせておく。


asyncメソッド内
・・・
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    Update();
);
・・・




Androider