Quantcast
Channel: かずきのBlog@hatena
Viewing all 1388 articles
Browse latest View live

Qt 製のアプリを DesktopBridge でストアに公開する方法

$
0
0

意外と簡単だったのでメモします。

環境

  • Windows 10 Fall Creators Update
  • Visual Studio 2017
    • Qt Visual Studio Tools
  • Qt 5.10.0 for Windows

手順

配布対象のアプリケーションの準備

とりあえず私は Qt 製アプリを持ってないので適当に Qt GUI Application を作って下準備をしました。 新規作成した段階だとプロパティの一般のページにある Windows SDK バージョンが何故か 8.1 になっていたので Windows 10 の 10.0.xxxxx.0 に変更しておきます。

そして、リリースビルドをして exe を出力しておきます。

配布対象の依存ファイルを収集

exe が出来たので依存してる dll とかをとってきます。windeployqt.exe というコマンドで exe が依存してる Qt の dll ファイルをコピーしてくれるので実行します。

私の場合はこんな感じになりました。

C:\Users\xxxx\source\repos\QtGuiApplication1\x64\Release>C:\Qt\Qt5.10.0\5.10.0\msvc2017_64\bin\windeployqt.exe QtGuiApplication1.exe
C:\Users\xxxx\source\repos\QtGuiApplication1\x64\Release\QtGuiApplication1.exe 64 bit, release executable
Adding Qt5Svg for qsvgicon.dll
Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5Qml Qt5Quick).
Direct dependencies: Qt5Core Qt5Widgets
All dependencies   : Qt5Core Qt5Gui Qt5Widgets
To be deployed     : Qt5Core Qt5Gui Qt5Svg Qt5Widgets
Warning: Cannot find Visual Studio installation directory, VCINSTALLDIR is not set.
Updating Qt5Core.dll.
Updating Qt5Gui.dll.
Updating Qt5Svg.dll.
Updating Qt5Widgets.dll.
Updating libGLESV2.dll.
Updating libEGL.dll.
Updating D3Dcompiler_47.dll.
Updating opengl32sw.dll.
Patching Qt5Core.dll...
Creating directory C:/Users/xxxx/source/repos/QtGuiApplication1/x64/Release/iconengines.
Updating qsvgicon.dll.
Creating directory C:/Users/xxxx/source/repos/QtGuiApplication1/x64/Release/imageformats.
Updating qgif.dll.
Updating qicns.dll.
Updating qico.dll.
Updating qjpeg.dll.
Updating qsvg.dll.
Updating qtga.dll.
Updating qtiff.dll.
Updating qwbmp.dll.
Updating qwebp.dll.
Creating directory C:/Users/kaota/source/repos/QtGuiApplication1/x64/Release/platforms.
Updating qwindows.dll.
Creating directory C:/Users/xxxx/source/repos/QtGuiApplication1/x64/Release/styles.
Updating qwindowsvistastyle.dll.
Creating C:\Users\xxxx\source\repos\QtGuiApplication1\x64\Release\translations...
Creating qt_bg.qm...
Creating qt_ca.qm...
Creating qt_cs.qm...
Creating qt_da.qm...
Creating qt_de.qm...
Creating qt_en.qm...
Creating qt_es.qm...
Creating qt_fi.qm...
Creating qt_fr.qm...
Creating qt_gd.qm...
Creating qt_he.qm...
Creating qt_hu.qm...
Creating qt_it.qm...
Creating qt_ja.qm...
Creating qt_ko.qm...
Creating qt_lv.qm...
Creating qt_pl.qm...
Creating qt_ru.qm...
Creating qt_sk.qm...
Creating qt_uk.qm...

VS のインストール場所の環境変数がないと言われていますが、欲しいのは Qt 関連のファイルだけなのでとりあえず大丈夫だと思いたい。

Windows アプリケーション パッケージ プロジェクトの作成

exe を作るプロジェクトと依存する dll が取得できたので次はソリューションに Windows アプリケーション パッケージ プロジェクトを追加します。そしてアプリケーションの項目に Qt のアプリケーションを追加します。 そして、 Windows アプリケーション パッケージ プロジェクトの下に Qt のプロジェクト名と同じフォルダを作って、その下に先ほど収集した依存する dll ファイルをまるっとコピーします。

現状こんな感じになってます。

f:id:okazuki:20171229164700p:plain

あとは、Windows アプリケーション パッケージ プロジェクトで右クリックしてストアからパッケージを作ります。今回はとりあえず x64 だけあればいいやって思ったので x64 だけにしてます。多くのプラットフォームで動かしたかったら x86 の方がいい感じですね。

x86 の appx に x64 のバイナリを含んでたりするとストアで審査落ちするので、こういう風に依存する dll みたいなバイナリをプロジェクトに含めるときはいい感じにする必要があるのですが… ターゲットが x86 か x64 でパッケージングするファイルをいい感じに仕分ける方法を知らないので、とりあえずどちらかのみを対象にするのが楽そうです。

ということでストアに提出するパッケージが出来ました。あとは、ストアに出すだけなので、以下のフォームから申し込みって感じですね。

Desktop Bridge Sign Up Form - Windows app development

まとめ

DesktopBridge はアプリの exe と依存するものを全て appx(実態はただの zip ファイル)に AppxManifest.xml というマニフェストファイルとともに固めるというだけのものになります。Windows 10 S で動作することが求められるため、外部から別途 exe や dll を所定のフォルダにおいて…というのは許されないという点にとりあえず気を付けていれば結構いけるんじゃないかと思います。

ということでお手持ちのアプリを Microsoft Store に出すのは、そう難しくないかも?という感じでした。


Visual Studio Installer の言語を変える

$
0
0

誰得な情報ですが…

--localeオプションで指定可能です。Visual Studio Installer の実行ファイルは C:\Program Files (x86)\Microsoft Visual Studio\Installerに入っている vs_installer.exeです。

コマンドプロンプトあたりで以下のように入力すると英語で起動してきます。

vs_installer.exe --locale "en-us"

インストーラーが英語で起動してきます。

f:id:okazuki:20180105095910p:plain

ということで新年最初の小ネタでした。

今年もこんな感じでメモをつらつらと書いていけたらと思います。多分 Mixed Reality 関連と DesktopBridge 関連が多めになる気がします。

foreach でループの index を知る方法

$
0
0

前に匿名型を使ってやりましたが Tuple 使った方が今風で値型なのでヒープ的にも優しいということでこうなりますね。

using System;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        staticvoid Main(string[] args)
        {
            var items = new[]
            {
                "item 1",
                "item 2",
                "item 3",
            };

            foreach (var (item, index) in items.Select((x, i) => (x, i)))
            {
                Console.WriteLine($"{index}: {item}");
            }
        }
    }
}

実行結果。

0: item 1
1: item 2
2: item 3

岩永さんのサイトのほうが詳しいですね。

ufcpp.net

2018 年はじめの INotifyPropertyChanged の実装方法

$
0
0

前にこんな記事を書きました。

blog.okazuki.jp

まぁ別にこの時と何かしら INotifyPropertyChanged を実装するために使える機能が増えたりしてないので状況が変わったわけではないのですが…。現実問題としてどういうものを選択するのかということをつらつらと書いてみたいと思います。

実際の業務で使用するとした場合に選択する方法

多分、大人しく INotifyPropertyChanged を実装した BindableBase クラスを作ってコードスニペットの組み合わせです。

ライブラリを使う場合は Prism.Core を入れて Visual Studio の拡張機能に Prism Template Pack を入れて propp コードスニペットで OK です。 基本クラスの縛りは嫌ですが、何かしら全体に波及する機能を簡単に追加するための手段としては親クラスは C# でとても簡単に実現できる手段だと思ってます。例えば setter で呼び出す SetProperty メソッドで DataAnnotations によるバリデーションを実行するとかいう処理を入れたい場合は、親クラスで作りこむのが一番簡単ですよね?多分。

Rx がいけそうな環境なら ReactiveProperty を使うと思います。

Roslyn Analyzer

これも Visual Studio 2015 からある機能なので、新しいものではないですが、C# といえばという Top 2 のお二方が実装しているものがあります。

ufcpp.net

github.com

これで生成されるコードと用意されているカスタマイズポイントで満足できる場合は使ってもいいかもしれません。 でも実際に使うなら、このコードを参考にしながら自作 Analyzer を作ることを試みるかも。自分の要件に従って作った方がつぶしが効くのかなぁと思います。

まとめ

なかなか決め手になる楽な方法がないなぁという印象です。 ちなみに今はコードスニペットで頑張ってます!

なんだかんだで setter / getter にコードを好きに書けるので色々つぶしが効くんですよね。

ReactiveProperty v4.0.0 をリリースしました

$
0
0

Reactive Extensions の v4.0.0 が出るまで待とうと思ってたのですが、一向に出る気配がないので Reactive Extensions のバージョンは v3.1.1 のままですが ReactiveProperty v4.0.0 をリリースしました。 Reactive Extensions の v4.0.0 がリリースされたら(いつだろう)Rx のバージョンだけ上げようと思います。

インストール

いつも通り NuGet からインストールできます。

www.nuget.org

新しい試み

リリースページ

GitHub のリリース機能使ってみた。

github.com

みんな使ってるから気になったので使ってみました。作るの楽でいいですね。

ドキュメント

今まで README.md につらつらと書き連ねてたものを MkDocs を使って書き直してみました。Sphinx も最初使おうとしたのですが Markdown で書きたいと思ってた時に、後付けのものよりは最初から Markdown を前提に作られてるもののほうが楽でした。

www.mkdocs.org

書き直したドキュメントはこちらです。

runceel.github.io

まだ、Xamarin.Forms での使い方書いてないので書かなきゃ…。

まとめ

読書メーター の iOS 版で採用していただいたり。

bookmeter.com

紅白歌合戦のアプリでも採用していただいたり

スクエニさんで使われてるローカライズツールでも使われたたり

cedil.cesa.or.jp

結構色々なところで使っていただいてるみたいで嬉しい限りです。

今後も、メンテナンスは続けていこうと思いますのでよろしくお願いいたします。

npm does not support Node.js v9.3.0 のなおしかた

$
0
0

いくつになってもエラーや警告メッセージを無意識に読み飛ばしてしまう癖とはなくならないものです。

ということで、久しぶりに npm を使ってツールを入れようとしたら以下のようなメッセージが出ました。

npm WARN npm npm does not support Node.js v9.3.0
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8.
npm WARN npm You can find the latest version at https://nodejs.org/

無意識に読み飛ばして、インストールしたつもりになったツールのコマンドを叩いたところで入ってなくて「あれ?」ってなりました。

なおしかた

以下のコマンドを実行して一回 npm をアンインストールします。

npm uninstall -g npm

そして、Node.js のサイトからインストーラーを落としてきて再インストール。 これでなおりました。

参考

Stackoverflow は素晴らしい。

stackoverflow.com

Word で数式を入力する方法 2018年1月現在

$
0
0

なんか数日前にちょろっと話題になってるのを見ました。

togetter.com

タイトルだけ見ると、まるで Word で数式を入力する機能が削除されて大変!!という風に見えますがそういうわけではありません。

まとめにもある、SATO Naoki (Neo) さんの呟きにもある通り、下位互換のために残されていた古の数式エディターの機能が消えたということになります。 現行の数式エディターは残ってます。

一部のまとめサイトでは、数式エディターが消えたので理系なら TeX で書けばみたいな論調のコメントだけ抜き出してるものもありますが、こういうまとめはちょっと…という感じですね。

数式を入力しよう

ということで、今現役の方法の数式の入力方法は以下になります。

リボンの挿入タブの数式を選択。

f:id:okazuki:20180114171948p:plain

数式を挿入を選択したら、あとはリボンの数式のデザインタブでぽちぽちすれば書けます。

f:id:okazuki:20180114172410p:plain

私は詳しくないのですが LaTeX の形式でも数式をかくことが出来ます。

f:id:okazuki:20180114184047p:plain

ということで、良い数式ライフを! (卒論書く人達は頑張ってください)

参考

support.office.com

Office での LaTeX の数式入力 – Office Blogs

ケーブルで繋いで 2 台の PC のマウスとキーボードを共有できる変なケーブル買って見た

$
0
0

標題通りの物を買いました。

USB で繋いでインストールされるソフトを入れないといけないのがちょっと難点ですが、まぁそれをのぞけば2台の PC の画面がまるでくっついたみたいにマウスカーソル移動させれるのが楽しいですね。 クリップボードも共有されるので、片方の PC でコピーしたファイルをもう一方の方でペーストすることもできます。便利だ。

ということで、家で半分以上眠っていた Macbook Pro と Surface Pro を繋いで見ました。ということで、この記事も Macbook Pro の上の Chrome に対して Surface Pro のキーボードから打ち込んでいます。

ちょっと慣れが必要だけど気に入ったかも。


ReactiveProperty v4.1.0 をリリースしました

$
0
0

昨夜 id:neueccさんがプルリクくれたので取り込みました。

github.com

www.nuget.org

追加機能

便利ではあるのですが、たまに不便な ReactiveProperty / ReadOnlyReactiveProperty が勝手に UI Thread にイベントをディスパッチする機能があります。これはインスタンス生成時に Scheduler を指定することで制御は出来るのですが、その他にも UI にエラー通知するための INotifyDataErrorInfo の実装とかもあったりして Model レイヤーで使うにはオーバースペックな機能があったりしました。

これを解決するために軽量な ReactivePropertySlim / ReadOnlyReactivePropertySlim が追加されました。良ければ試してみてください!

JXUGC #24 春の App Center 祭りで発表してきました

ReactiveProperty v4.2.0 をリリースしました

$
0
0

github.com

ReactiveProperty と ReadOnlyReactiveProperty に IEqualityComparer で値の比較条件を指定できるようにしました。

@soi013 さんプルリクありがとうございます。

導入はいつも通り nuget から!

www.nuget.org

pfx を作って appx に署名するまで

$
0
0

いつも忘れてしまうのでメモ。

makecert -r -pe -n "CN=XXXX" -eku 1.3.6.1.5.5.7.3.3 -pe -sv my.pvk my.cer
pvk2pfx -pvk my.pvk -spc my.cer -pfx my.pfx
makeappx.exe pack /d .\dirpath /p appxpath.appx /l
signtool sign /fd SHA256 /a /f .\my.pfx .\appxpath.appx

Android 版 Fly Delta アプリでチェックイン時にエラーになる問題と回避方法(と妄想)

$
0
0

先日シアトル出張があったときに Fly Delta アプリで飛行機のチェックインをしようとしたんですよね。

play.google.com

そしたら、パスポートの情報を入力するところで誕生日と有効期限の日付がエラーになってしまいチェックインできませんでした。

そういえば、前に何処かに行くときにも同じエラーにぶち当たった記憶がうっすらと浮かんできた。 その時は確か手持ちの iPhone を使ってチェックインした記憶がうっすらと…。

対応方法

Android しか手持ちにない場合どうすればいいか?というところですが、以下の方法でエラーが出ずにチェックインできるようになります。

Android の設定のシステムのところにある言語と入力から言語を English (United States) に変更。 その後にアプリを再起動してチェックインすると日付のエラーも消えてさくっと入れます。

妄想

Fly Delta の日付入力は月と日と年をドロップダウンから選択する形式です。そのためフリー入力とは違い入力ミスによるフォーマットエラーは起きません。もちろんありえない日付を入力(パスポートの有効期限が過去の日付とか)を入力することでエラーが起きる可能性はありますが、ここではちゃんとした日付を入力してもエラーになるので根本的に何かが間違ってる。

スクリーンショットをとるのを忘れてたので記憶での話になるのですが月のところが日本語でも January, February, ... という選択肢だったのでもしかすると SimpleDateFormat クラスのフォーマットが英語前提になってるのかもしれませんね。こんな感じに。

import java.lang.*;
import java.util.*;
import java.text.*;

publicclass Program {
    publicstaticvoid main(String[] args) {
        test(Locale.ENGLISH);
        test(Locale.JAPANESE);
    }

    privatestaticvoid test(Locale l) {
        try {
            System.out.println("------------");
            System.out.println(l);
            DateFormat fmt = new SimpleDateFormat("MMM d, yyyy", l);
            System.out.println(fmt.format(new Date()));
            Date d = fmt.parse("December 14, 2018");
            System.out.println(d);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

実行するとこんな感じの結果になります。

C:\Projects\JavaEdu>java Program
------------
en
Feb 5, 2018
Fri Dec 14 00:00:00 JST 2018
------------
ja
2月 5, 2018
Unparseable date: "December 14, 2018"

まとめ

いろんな国に配るアプリの場合は基本のユースケースくらいは流して落ちないかということの確認大事だなと思いました。

そこで、実機 UI テストの出来る Visual Studio App Center ですよね!!

appcenter.ms

背景透明の印鑑の印影画像をPowerPointで作ろう

$
0
0

やった~!電子的な書類だ~!!と思ってダウンロードしてみるとこんなのがあるケースがありますよね。

f:id:okazuki:20180205144008p:plain

なんですか…印って…。ということでこういう場合は以下のようなフローで書きますよね。

  • PC で記入
  • 印刷
  • 押印
  • スキャンしてPDF化
  • メールで送信

電子とは。

ということで、こういうときに使える印影データを作ってみたいと思います。背景透明のね!!

まず、白い紙に印鑑を押してスマホで撮影します。(Office Lensとかでさくっと取り込んでもいいかも) 画像を取り込んだら PowerPoint に、その画像を張り付けます。

f:id:okazuki:20180205144440p:plain

画像を選択してリボンの書式にある背景の削除を選択します。

f:id:okazuki:20180205144614p:plain

まぁ、こんな感じで大体いい感じにいきません。

f:id:okazuki:20180205144716p:plain

こんなときは保持する領域としてマークを選択して、保持したいところ(この場合は印鑑押したときの赤い部分ですね)をなぞります。こんな感じに。

f:id:okazuki:20180205144846p:plain

因みに上では見やすいようになぞってますが、なぞる必要はなくて色の似てる広い領域があれば、その部分をクリックすると自動的に同じ色が続いてる部分は認識してくれます。いらないところを選んでしまったらCtrl+Zで戻るか削除する領域としてマークを選んで消し込んでいきます。

こんな感じに出来上がったら変更を保持を選択します。

f:id:okazuki:20180205145255p:plain

あとは図を右クリックして図として保存すると背景透明の png として保存できます。印鑑のまわりの余白が多い場合は画像を右クリックしてトリミングを選んで印影のまわりの余白は消してしまいましょう。

png 画像が出来たら、あとは書類に貼れば OK です!

f:id:okazuki:20180205145614p:plain

ちゃんと背景透明なので書類に予め書いてある「印」の字が透けて見えるのでいい感じです。 あとは、これを PDF に印刷して出せば画像貼りやがったな!!っていうのもばれないでしょう。

ということで本物の物理印鑑を押すことが重要ではないけど印鑑項目のある類の書類の場合はこういう感じで印影画像を作っておくと紙に印字するということがいらなくなります。

ではでは。

C# で何か出来るのか?まとめてみた

$
0
0

C# は好きな言語です。C# 1.0 が 2002 年 4 月に出てからもうすぐ16 年!?になろうとしています。 今でも結構イケてる部類にランキングしてると個人的に思ってる C# ですが何が出来るのか?というのをまとめてみたいと思います。C# をこれから始めようと思っている方や、プログラミングを始めようと思ってるけど何を勉強しようか迷っている方が C# を検討する上での参考になればと思います。

コンソールアプリケーション開発

誰もが一度は書く黒い画面に Hello world の文字列を印字するアプリケーションもコンソールアプリケーションです。C# でももちろん作ることが出来ます。以下のような OS に対応しています。

OS .NET Fw or .NET Core
Windows .NET Framework and .NET Core
macOS .NET Core
Linux .NET Core

.NET Core というものが作られてから(その前には Mono がありましたが、今回の記事では .NET Framework と .NET Core を対象にしたいと思います。Mono は Mono で頑張ってるので凄い)

将来的には .NET Core では npm でインストールできるツールみたいなものもサポートするみたいなので、 .NET Core で開発者向けツールみたいなものを作っておくと将来的には、多くの OS で実行できるコマンドラインツールを開発できるようになるかもしれませんね。

blogs.msdn.microsoft.com

引用
.NET Core will include a new deployment and extensibility mechanism for tools. This new experience is very similar to and was inspired by Node global tools. We are re-using the same syntax and much of the experience.

おすすめ度

  • .NET Frameworkでの開発:勉強用にはいいんじゃないかな
  • .NET Core での開発:ツールをインストールする仕組みが整備されたら化けるかも。真面目なツールは、.NET Core で作っておいてもいいと思う。

デスクトップアプリケーション開発

Windows アプリケーション開発は私好きです。

Windows Forms

C# 1.0 からあるやつです。 出自からして Embarcadero さんの(当時は Borland だったかな)作った Delphi や C++ Builder にあった VCL の影響を色濃く受けたと感じるやつですね。

GUI をデザイナーで手軽にぽとぺたと作ってサクサクっと作れるのは衝撃的でした。

ただ今風の UI を作るのは骨が折れる作業です。例えば Twitter クライアントにあるような以下のようなレイアウトをリスト表示したいとします。

f:id:okazuki:20180206202308p:plain

オーナードローというプログラムコードで座標計算しながらゴリゴリゴリゴリ書いていきます。苦行です。 テキストの折り返しや、画像の表示や添付されてる画像が複数ある場合はどういう風にレイアウトして並べるか?どれくらいの大きさにするか?全て愚直にコードで書いていきます。

辛い。

ということで、過去の資産がある場合以外には個人的には触れなくていいと思います。

WPF (Windows Presentation Foundation)

Windows Forms の後継として登場して流行らなかったテクノロジーです。 流行らなかったといっても、今風の UI を割と簡単に書けて Win32API などに割とカジュアルにアクセスできるうえに Windows 10 の API にも限定的だけどアクセスできるので、Windows アプリケーションを作る上では一番出来ることと、作りやすさのバランスがいいプラットフォームです。

Windows 上で動くデスクトップアプリケーションを作るなら、まず最初に検討してもおかしくないくらいの立ち位置にいます。

でも、ワクワクするような新機能の追加は、ここ最近のアップデートを見ている限り無いでしょう。悲しい。

後で紹介する UWP と異なり .NET Framework さえ入っていれば動くので Windows 7 ~ WIndows 10 まで幅広いプラットフォームで動くデスクトップアプリケーションが作れるのが強みです。

UWP (Universal Windows Platform)

Pure UWP

これは正式なカテゴリではないのですが、個人的にわけて説明します。素の UWP です。 Windows 10 で追加された全ての Windows 10 で動かすことが可能なプラットフォームです。

Windows 10 はパソコン、Suraface Hub、HoloLens、モバイル(モバイルは今後の機能アップはないらしい)、IoT 機器で動くため、いろんなところで動きます。さらに Microsoft ストアに登録すれば世界中の Windows 10 を使用している人に向けて公開できる点が WPF や Windows Forms と異なります。

Windows 10 で動くアプリを作る上で最初の選択肢として考えるといいでしょう。ただ、安全であることが求められるので例えば他のプロセスに介入したりとかいうことが出来ないです。スマートフォンアプリに近い雰囲気ですね。

Desktop Bridge

これは exe 形式のアプリを特定のルールに従って appx などの Microsoft ストアに提出できるような形にパッケージングすることが出来るという、いわゆる UWP だけでは辛いけど既存の exe 形式のアプリでは出来てたようなことをやりたい!ってときに使うテクノロジーです。

C# で作った WPF、 Windows Forms のアプリも当然パッケージング出来ます。結構色々なことが出来て…

  • 単一 exe のアプリは当然いける
  • 1 つのパッケージに複数の exe を入れて相互に起動しあったりプロセス間通信をするようなアプリも作れる
  • 普通の UWP に exe も混ぜ込んで相互に何らかの方法でプロセス間通信をして Pure UWP だけではできないことを実現するようなアプリも出来る。見た目 UWP で裏では exe がいろんなことしてるみたいなやつ。

ただ、完全に何でもできるというわけではなく、いくつか制限事項もあったりするので要注意ですね。

アプリのパッケージ化の準備 (デスクトップ ブリッジ) - UWP app developer | Microsoft Docs

おすすめ度

  • Windows Form:触れる必要があるまで触れる必要はないと思います。
  • WPF:Windows 7 以降を対象にするならコレ
  • UWP:Windows 10 以降を対象にするならコレ。
    • Pure UWP:まずはコレ
    • Desktop Bridge:Pure UWP で辛くなってきたらコレ

Web アプリケーション

クラウドが普及したおかげで Web アプリケーションを作って公開するハードルが凄く下がりましたよね。 素晴らしい。ということで、ネイティブアプリじゃなくてもいいなら Web アプリでしょ。

ASP.NET WebForm

C# 1.0 のころからある Web アプリケーションをまるでデスクトップアプリケーションを作るかのような感じで作ろうという野心的な試みの元作られたものです。本当にその通りの出来栄えで素晴らしいのですが、如何せん今の Web の仕組みにどっぷりのっかったアプリを作るような時代には Web っぽさを包み隠したフレームワークは合わなくなってきたんでしょうね。

デスクトップアプリケーションでいうところの Windows Forms のような立ち位置です。

ASP.NET MVC

明言されてないと思うのですが Ruby on Rails あたりで流行った作り方と同じノリで作れるようにしたものだと思ってます。WebForm が HTTP を隠匿していたのに対して MVC はいかに HTTP に対して自然にプログラミング出来るかというように作られてるように感じます。

.NET Framework のフル機能が使えるのですが、基本的に Windows サーバー上でしか動かないという柵はあります。

ASP.NET WebAPI

REST API を作るのにいい感じに作られた。MVC と似ている。似ているが故に同じような名前の API が別名前空間にあったりして同時に使うとちょっとヤヤコシイ印象を受ける。

ASP.NET Core

コンソールアプリケーションのところでも出てきた Core という名前ですね。 .NET Framework でも動くのですが、ここではとりあえずヤヤコシイので無視しておきます。

ASP.NET MVC と WebAPI をがっちゃんこして .NET Core 上で動くように再構築したようなものです。なので、Linux でも動きます。.NET Core は .NET Framework と比べてランタイムがヘビーじゃないので Docker なんかで動かしたい場合にはこちらのほうがいいと思います。

マイクロサービスとかクラウドネイティブだとかいうノリでアプリを作りたければ、これが最初の選択肢になるでしょう。

おすすめ度

  • ASP.NET WebForm:必要に迫られるまで触る必要はないと思う
  • ASP.NET MVC:フルの .NET Framework に縛られた状態で Web アプリを作りたければまずコレ
  • ASP.NET WebAPI:フルの .NET Framework に縛られた状態で WebAPI を作りたければまずコレ
  • ASP.NET Core:今からやるんなら最初に検討してもいい段階に入って来てると思う。

モバイルアプリ開発

ざまりんはいいぞ。

Xamarin

iOS, Android, UWP などの色んなプラットフォームで動くアプリを C# で書けるようにしようという野心的なやつ。凄い。

Xamarin Native

C# でコードを共有化しつつ画面は各プラットフォーム依存の方法で書きましょうというやり方。そのため、既存のスマホアプリの画面は原理的に完璧に再現できるという強さがある。 (サードパーティ画面部品とかがあった場合には、使うの辛かったりしますが、まぁ原理的には同じことが出来ないわけではない)

Xamarin.Forms

画面も XAML っていう WPF や UWP と同じようなマークアップ言語で共通的に書けるようにしようぜっていう野心的なやつ。WPF, UWP, Tizen など iOS や Android いがいにも色んなプラットフォームで動くものが作れるというところが強み。

画面を共通化してしまったが故に最大公約数の機能しかないが、プラットフォームごとにコードを書かないといけないけど、コントロールを書いたりレンダラーと呼ばれるカスタマイズする処理とかを書いたりすれば Xamarin Native よりすご~~~~~く大変だけど、既存のアプリの見た目と同じものは再現できるだろう。

だけど、そこまで見た目に凝るなら画面はプラットフォーム固有の方法で実装したほうがいいよねっていうのが個人的な感想。

まとめ

  • Xamarin:モバイルアプリ開発なら一択でしょう!!
    • Xamarin Native:見た目凝るならこっちのほうが幸せなことが多い
    • Xamarin.Forms:見た目そんなに凝らない(企業向けとか)なら画面までコード共通化できるので強い

ゲームを作りたい

Unity

Unity 社さんの作ってるゲームエンジンで、ちょっと古い C# で書ける。 スマホゲーム界隈で特にあつくて色んなゲームが Unity で作られてる。

DirectX (よく知らないので間違ってるかも)

硬派。よく知らないけど鬼みたいにコード書かないといけない。その代わりまぁ書けばなんでもできるしプリミティブなぶん性能もいいんでしょうね。

おすすめ度

  • Unity:ゲームを C# で書くなら最初に検討するものになると思います。
  • DirectX:Unity 使いましょう。どうしても DirectX が好きなら…?

VR / MR アプリを作りたい

最近流行りの VR やら MR のアプリです。HoloLens や Windows Mixed Reality のヘッドセットあたりで動くアプリが作れます。

Unity

これも Unity で作ります。ただ基盤は UWP なので UWP の知識もあるとなおよし。 これからの世界では、おそらく求められると思うのでここを攻めてみるのもありだと思います。

DirectX

ゲームと同じ。

おすすめ度

  • Unity:最初にこれ
  • DirectX:?

まとめ

ということで、適当につらつらと思いついたものを書いてみました。C# で出来ることと、その中で一番お勧めなものをまとめると以下のようになります。

対象 おすすめ
コンソールアプリケーション .NET Core
デスクトップアプリケーション UWP
Web アプリケーション ASP.NET Core
モバイルアプリ Xamarin
ゲーム Unity
VR / MR Unity

とまぁお勧めのテクノロジだけやってればいいと幸せなのですが C# みたいに歴史のある言語だと過去とのふれあいもどうしても必要になるので、必要に応じてやっていきましょう。


Desktop Bridge のアプリで UWP から同じパッケージ内の exe を起動する方法

$
0
0

表題の通りです。 UWP だけではできないことは DesktopBridge を使うことで実現できることもあるというわけなのでやってみましょう。

プロジェクトの作成

以下の 3 つのプロジェクトを作成します。

  • Windows アプリケーション パッケージ プロジェクト
    • 名前は任意ですが、ここでは LaunchApp という名前で作りました。
    • UWP がサポートするプラットフォームは、とりあえず最小もターゲットも Fall Creators Update にしました。(ここは私の好みなので、自分がサポートしたいバージョンに合わせましょう)
  • 空白のアプリ(ユニバーサル)を追加
    • 名前は任意ですが、ここでは LaunchApp.UWP という名前で作りました。
    • 最小とターゲットは Fall Creators Update(自分のサポートしたいターゲットに合わせて大丈夫です)
  • WPF アプリ(.NET Framework)を追加
    • 名前は任意ですが、ここでは LaunchApp.WPF という名前で作りました。

プロジェクトの設定

LaunchApp プロジェクトのアプリケーションの右クリックメニューから参照の追加で、LaunchApp.UWP と LaunchApp.WPF を追加します。

アプリケーションの下に追加された LaunchApp.UWP を右クリックしてエントリ ポイントとして設定します。

こんな感じになります。

f:id:okazuki:20180209202031p:plain

マニフェストへの exe の登録

LaunchApp プロジェクトの Package.appxmanifest を右クリックしてコードの表示をします。

Package タグに以下の xml 名前空間を追加します。

xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"

そして、Application タグの下に Extensions タグを以下のように追加します。

<Extensions><desktop:Extension Category="windows.fullTrustProcess"Executable="LaunchApp.WPF\LaunchApp.WPF.exe" /></Extensions>

ここに登録した exe が起動できます。注意点は1つしか登録できないところですかね。(多分)

UWP から exe の起動

ついに起動処理を書きます!といっても大したことはないですが。 まず、FullTrustProcessLauncher クラスを使うのですが、これはデスクトップデバイスファミリーのみで使えるので参照に追加します。

参照の追加で Universal Windows → 拡張 の中にある Windows Desktop Extensions for the UWP にチェックを入れます。バージョンが複数ありますが 14393 以上に入っています。

exe を起動するきっかけのボタンを MainPage.xaml に置きます。

<Page x:Class="LaunchApp.UWP.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:LaunchApp.UWP"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Button Content="Launch"Click="Button_Click" /></Grid></Page>

MainPage.xaml.cs で以下のコードを書きます。

using System;
using Windows.ApplicationModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace LaunchApp.UWP
{
    publicsealedpartialclass MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
        }
    }
}

FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync() で先ほど定義した Extension の exe が起動します。

実行して動作確認

こんな感じに動けば完成です。(Any CPU じゃなくて x86 とか x64 にして起動するのを忘れずに)

f:id:okazuki:20180209203524g:plain

DesktopBridge アプリで UWP アプリと Win32 アプリの連携方法

$
0
0

1つ前の記事で起動方法は紹介しました。

blog.okazuki.jp

起動は出来たら次したいことは連携ですよね。ということでしてみましょう。

仕組み

UWP の AppService を使ってやるのがお勧めです。

docs.microsoft.com

UWP 側で AppService を作っておいて、それを介して WPF などの Win32 アプリと UWP のアプリが連携するようにします。 なのでこんな感じで動くような雰囲気ですね。

  • UWP アプリ起動
  • Win32 アプリ起動
  • Win32 アプリから AppService へ接続
    • UWP アプリ側で AppService が起動する
  • 接続を介してやり取り

やってみよう

私が最後に UWP を勉強したときは別プロセスで AppService が起動してたような気がするのですが最近は UWP アプリと同じプロセスで可能になっててびっくりしました。

docs.microsoft.com

App.xaml.cs の編集

OnBackgroundActivated をオーバーライドして AppServiceTriggerDetails が来てたら AppServiceConnection を取得して各種イベントを初期化します。 メッセージが飛んで来たら RequestReceived イベントが来るのでここで色んな処理をします。

今回は MainPage のテキストを更新するための処理を呼び出しています。 注意点は必ずしも UI スレッドでイベントが発生するわけではないので UI にダイレクトにアクセスするのは NG です。

private AppServiceConnection _appServiceConnection;
private BackgroundTaskDeferral _appServiceDeferral;

protectedoverridevoid OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    base.OnBackgroundActivated(args);

    if (args.TaskInstance.TriggerDetails is AppServiceTriggerDetails appService)
    {
        _appServiceDeferral = args.TaskInstance.GetDeferral();
        args.TaskInstance.Canceled += TaskInstance_Canceled;
        _appServiceConnection = appService.AppServiceConnection;
        _appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived;
        _appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
    }
}

privatevoid AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
    _appServiceDeferral?.Complete();
}

private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
    var d = args.GetDeferral();

    var message = args.Request.Message;
    var input = message["Input"] asstring;

    await MainPage.Current?.SetTextAsync(input);
    await args.Request.SendResponseAsync(new ValueSet
    {
        ["Result"] = $"Accept: {DateTime.Now}"
    });
    d.Complete();
}

privatevoid TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    _appServiceDeferral?.Complete();
}

MainPage 側ではこんな感じ。

<Page x:Class="LaunchApp.UWP.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:LaunchApp.UWP"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><TextBlock x:Name="textBlock"Style="{ThemeResource HeaderTextBlockStyle}" /><Button Content="Launch"Click="Button_Click"HorizontalAlignment="Center"VerticalAlignment="Center"/></Grid></Page>

コードビハインドでは、グローバルにページのインスタンスにアクセスできるような static 変数へのインスタンスへの格納と、テキストを設定する処理を書いています。 テキストを設定する処理では UI スレッド以外からのアクセスにも対応する処理を入れてます。

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace LaunchApp.UWP
{
    publicsealedpartialclass MainPage : Page
    {
        publicstatic MainPage Current { get; private set; }

        public MainPage()
        {
            this.InitializeComponent();
            Current = this;
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
        }

        public async Task SetTextAsync(string text)
        {
            void setText()
            {
                textBlock.Text = text;
            }

            if (Dispatcher.HasThreadAccess)
            {
                setText();
            }
            else
            {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    setText();
                });
            }
        }
    }
}

そして、マニフェストに AppService があることを定義します。このとき定義するのは UWP アプリ(今回の場合はLaunchApp.UWP)ではなく Windows アプリケーション パッケージ プロジェクト(今回の場合は LaunchApp) に定義します。

LaunchApp の Package.appxmanifest を開いて以下のように AppService を定義します。

f:id:okazuki:20180210123054p:plain

これで具体的には、以下のようなタグが Application タグの下に追加されます。

<Extensions><!-- ここから --><uap:Extension Category="windows.appService"><uap:AppService Name="InProcessAppService" /></uap:Extension><!-- ここまで --><desktop:Extension Category="windows.fullTrustProcess"Executable="LaunchApp.WPF\LaunchApp.WPF.exe" /></Extensions>

WPF 側の実装

あとは MainWindow でクリックされたときに AppServiceConnection を作って繋ぎに行ってます。

<Window x:Class="LaunchApp.WPF.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:LaunchApp.WPF"mc:Ignorable="d"Title="MainWindow"Height="350"Width="525"><StackPanel><TextBox x:Name="inputTextBox" /><Button Content="Send"Click="Button_Click" /><TextBlock x:Name="logTextBlock" /></StackPanel></Window>

コードビハインドで実際の通信処理をしてます。

using System;
using System.Diagnostics;
using System.Windows;
using Windows.ApplicationModel;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;

namespace LaunchApp.WPF
{
    publicpartialclass MainWindow : Window
    {
        private AppServiceConnection _appServiceConnection;
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            if (_appServiceConnection == null)
            {
                _appServiceConnection = new AppServiceConnection();
                _appServiceConnection.AppServiceName = "InProcessAppService";
                _appServiceConnection.PackageFamilyName = Package.Current.Id.FamilyName;
                var r = await _appServiceConnection.OpenAsync();
                if (r != AppServiceConnectionStatus.Success)
                {
                    MessageBox.Show($"Failed: {r}");
                    _appServiceConnection = null;
                    return;
                }
            }

            var res = await _appServiceConnection.SendMessageAsync(new ValueSet
            {
                ["Input"] = inputTextBox.Text,
            });
            logTextBlock.Text = res.Message["Result"] asstring;
        }
    }
}

実行して動作確認

こんな感じで動けば成功です。

f:id:okazuki:20180210131023g:plain

コード

プロジェクトは GitHub に公開しています。GitHub のほうのコードは、ここでのコードをちょっと改造して UWP -> WPF 方向の通信も追加しています。

github.com

UWP の画面遷移でいい感じのアニメーションをさせよう

$
0
0

Connected Animation というものを使うと出来ます。

ConnectedAnimationService.GetForCurrentView() で取得した ConnectedAnimationService に対して画面遷移前と画面遷移後で対応するコントロールの紐づけをしてやる感じです。なので、画面遷移前に画面遷移前のページでアニメーションさせたいコントロールを登録して、画面遷移先でもアニメーションさせたいコントロールを指示するという処理が必要になります。

こんなイメージです。

// 画面遷移前
var a = ConnectedAnimationService.GetForCurrentView();
a.PrepareToAnimate("text", textBlock);
a.PrepareToAnimate("button", button);

Frame.Navigate(typeof(NextPage));


// 画面遷移先の OnNavigatedTo メソッドにて
var a = ConnectedAnimationService.GetForCurrentView();
a.GetAnimation("text")?.TryStart(textBlock);
a.GetAnimation("button")?.TryStart(button);

PrepareToAnimate や TryStart に渡してるのがアニメーションさせたいコントロールです。こんな感じで動きます。

f:id:okazuki:20180211233700g:plain

ListView の要素でアニメーション

普通は ListView タップしたら詳細画面に行くってパターンが多いですよね。そのときしゅっとアニメーションしたらかっこいい…!やってみよう。

データの入れ物作ります。

publicclass Person
{
    publicstring Id { get; set; } = Guid.NewGuid().ToString();
    publicstring Name { get; set; }
}

とりあえずお試しなので App クラスあたりにグローバルでリスト持たせておきましょう。

publicstatic Person[] People { get; } = Enumerable.Range(1, 100)
    .Select(x => new Person
    {
        Name = $"tanaka-{x}",
    })
    .ToArray();

MainPage.xaml で以下のようにバインドします。

<Page x:Class="App14.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App14"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><ListView x:Name="listView"><ListView.ItemTemplate><DataTemplate x:DataType="local:Person"><Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><TextBlock x:Name="textBlockName"Text="{x:Bind Name}"Style="{ThemeResource BodyTextBlockStyle}" /><Border x:Name="border"Background="Red"Width="50"Height="50"Margin="5"Grid.Column="1" /></Grid></DataTemplate></ListView.ItemTemplate></ListView></Grid></Page>

コードビハインドでデータを ListView に追加しておきます。

using Windows.UI.Xaml.Controls;

// 空白ページの項目テンプレートについては、https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x411 を参照してくださいnamespace App14
{
    /// <summary>/// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。/// </summary>publicsealedpartialclass MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            listView.ItemsSource = App.People;
        }
    }
}

ListView を押したら画面遷移するようにします。ItemClick イベントを拾って

<ListView x:Name="listView"IsItemClickEnabled="True"SelectionMode="None"ItemClick="listView_ItemClick">

ListView の PrepareConnectedAnimation で下準備して画面遷移します。

privatevoid listView_ItemClick(object sender, ItemClickEventArgs e)
{
    listView.PrepareConnectedAnimation("text", e.ClickedItem, "textBlockName");
    listView.PrepareConnectedAnimation("border", e.ClickedItem, "border");
    Frame.Navigate(typeof(NextPage), ((Person)e.ClickedItem).Id);
}

遷移先のページを作ります。

<Page x:Class="App14.NextPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App14"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><StackPanel VerticalAlignment="Center"HorizontalAlignment="Center"><TextBlock x:Name="textBlock"Style="{ThemeResource HeaderTextBlockStyle}" /><Border x:Name="border"Width="100"Height="100"Background="Red" /></StackPanel><Button x:Name="button"Content="Back"Click="Button_Click" /></Grid></Page>

OnNavigatedTo メソッドでアニメーションの紐づけを行います。

private Person _target;
protectedoverridevoid OnNavigatedTo(NavigationEventArgs e)
{
    _target = App.People.First(x => x.Id == (string)e.Parameter);
    textBlock.Text = _target.Name;

    var a = ConnectedAnimationService.GetForCurrentView();
    a.GetAnimation("text")?.TryStart(textBlock);
    a.GetAnimation("border")?.TryStart(border);
}

戻る方向もアニメーションをつけます。遷移先のページから戻る前にアニメーションの下準備をして…

privatevoid Button_Click(object sender, RoutedEventArgs e)
{
    var a = ConnectedAnimationService.GetForCurrentView();
    a.PrepareToAnimate("text", textBlock);
    a.PrepareToAnimate("border", border);
    Frame.Navigate(typeof(MainPage), _target.Id);
}

戻った先でアニメーションを開始します。

<Page x:Class="App14.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App14"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><ListView x:Name="listView"IsItemClickEnabled="True"SelectionMode="None"ItemClick="listView_ItemClick"Loaded="listView_Loaded"><ListView.ItemTemplate><DataTemplate x:DataType="local:Person"><Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><TextBlock x:Name="textBlockName"Text="{x:Bind Name}"Style="{ThemeResource BodyTextBlockStyle}" /><Border x:Name="border"Background="Red"Width="50"Height="50"Margin="5"Grid.Column="1" /></Grid></DataTemplate></ListView.ItemTemplate></ListView></Grid></Page>
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

// 空白ページの項目テンプレートについては、https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x411 を参照してくださいnamespace App14
{
    /// <summary>/// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。/// </summary>publicsealedpartialclass MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            listView.ItemsSource = App.People;
        }

        private Person _scrollTarget;

        protectedoverridevoid OnNavigatedTo(NavigationEventArgs e)
        {
            if (e.Parameter isstring id)
            {
                _scrollTarget = App.People.FirstOrDefault(x => x.Id == id);
            }
        }

        privatevoid listView_ItemClick(object sender, ItemClickEventArgs e)
        {
            listView.PrepareConnectedAnimation("text", e.ClickedItem, "textBlockName");
            listView.PrepareConnectedAnimation("border", e.ClickedItem, "border");
            Frame.Navigate(typeof(NextPage), ((Person)e.ClickedItem).Id);
        }

        private async void listView_Loaded(object sender, RoutedEventArgs e)
        {
            if (_scrollTarget == null)
            {
                return;
            }

            listView.ScrollIntoView(_scrollTarget);
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
            {
                var a = ConnectedAnimationService.GetForCurrentView();
                await Task.WhenAll(
                    listView.TryStartConnectedAnimationAsync(a.GetAnimation("text"), _scrollTarget, "textBlockName").AsTask(),
                    listView.TryStartConnectedAnimationAsync(a.GetAnimation("border"), _scrollTarget, "border").AsTask());
            });
        }
    }
}

ポイントは ListView の Loaded イベントでアニメーションをしていることです。 OnNavigatedTo だとタイミングが早すぎるのか例外が出てしまいました。

そして、ListView で表示対象のコントロールが出てくるまでスクロールしてアニメーションをしています。アニメーションは、Dispatcher を使って少し遅らせてやってます。これをしないと自分のところではアニメーションしてくれなかった…。

ドキュメントではそんなことしてないんだけど。謎い。

docs.microsoft.com

実行するとこんな感じです。

f:id:okazuki:20180212001639g:plain

Visual Studio 2017 15.5 + Windows 10 Fall Creators Update で UWP をデバッグ実行するとアプリ終了後に Visual Studio がクラッシュする

$
0
0

はい。辛い。

どうも根深いみたいで下記サイトに回避方法が書いてありました。

developercommunity.visualstudio.com

私は devenv.exe.config の AppContextSwithcOverrides タグを以下のようにする方法で回避できました(設定画面でいじるだけでは効果がなかった…)

<AppContextSwitchOverrides value="Switch.System.Threading.ThrowExceptionIfDisposedCancellationTokenSource=false;Switch.System.Windows.Forms.DoNotSupportSelectAllShortcutInMultilineTextBox=false;Switch.System.Windows.Input.Stylus.DisableStylusAndTouchSupport=true" />

まぁ次の Windows 10 のアップデートまでの回避策になることを祈って。

追記

これやって直ったと思ってしばらく使ってたら、またクラッシュした。 ダメだ、誰か回避方法を知ってたら教えてください。

Google Home の Hello world を Azure も使って書いてみよう

$
0
0

本日以下の勉強会に参加してきました。

smarthacks.connpass.com

なんとなく Google Home 対応アプリの作り方の雰囲気がわかったので復習もかねてやってみたいと思います。 ちなみに Azure 使います。

Dialogflow で Agent を作成

以下のページに移動して SignIn します。

dialogflow.com

そして Agent を新規作成します。 この Agent というのがアプリの単位になるっぽいですね。

ここでは HelloWorld にしました。

f:id:okazuki:20180224213427p:plain

Intent の作成

次に言われたことが、どんな操作を望んでいるものなのかというのを表す Intent を作成します。 Default Welcome Intent が規定の最初に呼び出されるものみたいですね。デフォルトで返答に「こんにちは!」が設定されています。

CREATE INTENT ボタンを押して Intent を作ります。名前を Greet にして Training phrases に入力となる文字列を指定します。とりあえず「こんにちは」と入力しておきます。

次に応答です。Responses には「ようこそ!」とうっておきましょう。

動作確認

やってくれることは1つだけですが、立派な Dialogflow です。では動作確認してみましょう。 画面右側に Try it now と書いてある領域があると思います。そこに「こんにちは」と打ち込んでみると以下のようになります。 ちゃんとできてますね!

f:id:okazuki:20180224214332p:plain

シミュレーターで動作確認

Intent が正しく構成されているのがわかったのでアプリとしての動作確認をしてみたいと思います。 ハンバーガーメニューを開いて Integrations を選択します。そして Google Assistant を選びます。

Explicit Invocation に最初に呼ばれる Intent を選択します。とりあえずは Default Welcome Intent で OK。

そして TEST を選択します。

f:id:okazuki:20180224214717p:plain

Actions on Google の画面に切り替わります。ここでアプリ名の設定とか実際の動作のテストとかが出来ます。

画面左上の Overview を押してみましょう。App Information でアプリの色々な設定をします。 Name や Pronantiation を適当に入れる

f:id:okazuki:20180225001114p:plain

SAVE を押すとエラーになるテキスト入力項目がいくつかあるので適当に埋めます。SAVE をすると画像をアップロードしろと言われますがそれはとりあえず無視します。

そして画面左の Simulator を選択します。 適当にぱちぱちうつと動いた!

f:id:okazuki:20180224222556p:plain

Azure と繋いでみよう

こういう感じで色々定義していけば対話操作がそれっぽいのが出来るのが Dialogflow なんですが、外部サービスを呼びたいとか込み入ったロジックを走らせたいときには力不足なのは否めません。

ということで Intent で Webhook が呼べます。

Webhook の受信先を作る

ということでデフォルトでは Firebase の Functions が使われるのですが、あえての Azure でいってみましょう。Azure Functions を使いたかったのですが actions-on-google が express を前提にしてるように見えたのでとりあえずは Web App に express 製のアプリをのせてお茶を濁したいと思います。

適当なフォルダで以下のコマンドを叩きます。

npm init
npm install --save express
npm install --save actions-on-google
git init

.gitignore を作って以下のように node_modules を除外しておきます。

node_modules/

ここらへんで適当にコミットしておきましょう

git add --all
git commit -m "init"

app.js を作成して以下のようにします。

const express = require('express');
const bodyParser = require('body-parser');
const DialogflowApp = require('actions-on-google').DialogflowApp;

const app = express();
app.use(bodyParser.json());

app.post('/googlehome', (req, res) => {
  console.log(JSON.stringify(req.body));
  const app = new DialogflowApp({
    request: req,
    response: res
  });

  app.ask("マイクロソフト アジュールから こんにちは。終わる場合は終了と言ってください。");
});

app.listen(process.env.PORT || 1337);

そして、package.json で Azure で使う node.js のバージョンを指定するために engine の項目を追加します。

{
  "name": "googlehomeonazure",
  "version": "1.0.0",
  "description": "Google home on azure",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "actions-on-google": "^1.8.2",
    "express": "^4.16.2"
  },
  "engines": {
    "node": ">=6.9.1"
  }
}

ここらで commit しておきます。

git add --all
git commit -m "OK"

Azure に適当な名前で Web App を作成します。作成したら、デプロイオプションでローカル git の構成をしておきます。デプロイ資格情報も設定してなかったら設定しましょう。

あとは remote に Web App の概要に表示されてる git クローン URL を追加して push します。

git remote add origin <Azure Portal からゲットした URL>
git push origin master

これでデプロイ資格情報に設定した情報でログインすると push がはじまりデプロイが始まります。

Dialogflow 側の設定

Dialogflow の Fulfillment で Webhook を有効にします。URL に先ほど作成した node.js で待ち受けてる URL を指定します。こんな感じに。

f:id:okazuki:20180224234928p:plain

では Greet のインテントから Webhook を叩くようにします。一番下の Fulfillment の Enable webhook call for this intent をオンにします。Responses もいらないので消しておきましょう。

f:id:okazuki:20180224235142p:plain

最後に、一応アプリを終了するための Intent を作っておきます。これはなくても動くけど動きっぱなし防止のために。

Finish という名前で「終了」というワードで Text response で「さようなら」を返す感じで作ります。そしてアプリの終了であるということを表す Set this intent as end of conversation をオンにします。

f:id:okazuki:20180224235345p:plain

動作確認

では、動かしてみましょう。 Google アシスタントで開発に使用したのと同じ google アカウントでサインインしてると使えます。私の Android 携帯だとこんな感じで。

f:id:okazuki:20180225000040p:plain

Android での動作確認が出来たので Google Home でも!

まとめ

次は Azure Functions で出来たらいいなぁ。

Viewing all 1388 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>