DPI機能も正式公開になりました。Scalingと呼びます。Guideをまず参照。Scalingの前提条件は以下のとおりです。4.6.2以降であることマニフェストのdpiAwarenessがPerMonitorであること最初に対応OSについて。DPIについてはさっくり放置する方針のようです。8.1については従来どおり独自対応で行くしかないという方向で確定と。10推しの現況では、それ以前のOSに対してリソースの割り当てがないのだろうと思います。8.1は過渡期のOSであることは否定できない感じはします。次に新しいdpiAwarenessについて。従来のdpiAwareに対して、新しくマニフェスト(app.manifest)に導入されました。Update以降で、かつdpiAwarenessが指定されていれば、この指定の方が有効になる、ということのようです。例として、サンプルでの指定方法。Awareの指定になっています。Awareとなり、仮想スケーリングがかかります。8.1上で全くスケーリングがかからなくなってしまうので、それを避けたかったのかなと思いますが、何か要らぬ手間がかかっている気がします。これらの基本条件に対して、コンフィグ(App.config)の方でSwitch.System.Windows.DoNotScaleForDpiChangesを指定すると、その値によって設定をオーバーライドできます。Scalingを有効にする例として、有効にする場合(supportedRuntimeは無関係)。Scalingは使いたいような場合でしょうか。DPIに応じて変化するような独自コントロールがあるのでもなければ、4.6.2の機能がなくても困りませんし。条件としては以上です。8.1上で仮想スケーリングに甘んじたくなければ、引き続き独自対応が必要になります。10以降も独自対応で通したい場合もあるかもしれません。Scalingは発動しないようです。4.6.2より前では、VisualTreeのルートたるWindowから傘下のコントロールにDPI変化を伝えるためには、独自に伝播ルートを張る必要がありました。Scalingが発動したときは、各コントロールのOnDpiChangedメソッドかImage等のDpiChangedイベントで自動的に伝播されます。あれば、独自対応の場合でもこのルートを利用した方が楽ですが、この伝播はVisualTreeHelper.SetRootDpiメソッドで発生させることができます。したがって、独自対応でスケーリングさせると同時に、これを実行するようにすることで伝播ルートを統一できます。Scalingに任せるように切り替えることは意外と難しくないです。自作ライブラリでは、XAMLから指定可能なWillForbearScalingIfUnnecessaryプロパティでこれが可能なようにしています。area(NCA、ウィンドウの枠のクローム部分)のスケーリングに関してエントリが出ています。APIを追加するという話ですが、これまで手つかずだったNCAのスケーリングの話もあります。scaling.とありますが、実際に試してみると「いや、効いてないし......」という状態。そこで、NCAのスケーリングを有効にする新APIのEnableNonClientDpiScalingを実行しようとすると、WPFでウィンドウハンドルを取得できるタイミングとしてはおそらく最早のWindow.OnSourceInitializedメソッド内では成功しないし、エラーコードにも有意な情報がなく。supportWPFでウィンドウメッセージを捕捉するにはウィンドウハンドルが必要なので、いずれにしてもWindow.OnSourceInitializedメソッドより早くはできなくて、このときにはこのメッセージは通り過ぎた後らしくて捕捉できない、と手が出せない状態。出せるものから出していくという姿勢は否定しませんが、既にとっ散らかる兆候を見せているので、出来上がったときにはなるべくまとまった形になっているといいな、というのがささやかな希望です。[追記]EnableNonClientDpiScalingの効果は、WinFormsであれば簡単に確認できます。DPI機能が試せるようになっています。いっても普通に動きすぎて特記することもなく、またプレビュー段階であまり深入りするのも意味がある気がしないので、簡単にまとめてみます。Rawでダウンロードできます。Microsoft/WPF-Samples/PerMonitorDPIこれを読むと、試すには以下が条件になっています。8.1については記載なし)方法としては、基本的にapp.manifestのdpiAwareをtrue/PMにしておけば終わりです。WPFのレイアウトシステムに乗ったUIであれば、他に何も要りません。それでは対応できない場合のために個別に救済策が用意されていますが、引っ掛かることがなければ使う機会はないと思います。DPI変化は、VisualのレベルでOnDpiChangedメソッドが用意されているので、これをオーバーライドすることで感知できます。WindowやImageにはDpiChangedイベントが追加されているので、これでも感知できます。細かくは、DpiScaleInfoはDpiScaleに名前が変わりました。DpiChangedイベント用にDpiChangedEventHandlerとDpiChangedEventArgsが追加されたので、これだけから新旧のDPIを取得できます。Update以降の場合です。それ以前の場合は従来どおり自前の方法で取得する必要があります。テスト簡単に動作をテストするアプリを書きました。実際のスケーリングとOnDpiChangedやDpiChangedは結びついていない。OnDpiChangedをオーバーライドして変えてもスケーリングは操作できない。VisualTreeHelper.SetRootDpiを実行するとVisualTreeで波及的にOnDpiChangedを実行させることができるが、これも実際のスケーリングとは関係しない。WM_DPICHANGEDメッセージを受信したときにhandledをtrueにするとスケーリングを抑止できる。実行時にスケーリングさせないよう動作を変えることも可能。8.1に対応させる気があるかどうか分からないので、保険としてWM_DPICHANGEDを受けてスケーリングを直接起こさせる手もあるかと思ったのですが、そうは行かないようで。一応、このアプリのレポジトリ。emoacht/WpfPlatformDpiTest何にせよ、すべては現段階での話です。10のインタラクティブなトースト通知はデスクトップアプリからも出せます。その前提として、アクションセンター用のINotificationActivationCallbackを実装する必要があります。別にトースト通知がアクションセンターに入っている状態に限らないので、正確な表現ではありませんが。8から形式が変わっています。8式でもそのまま出せるので、インタラクティブな機能が必要ならこちらを使うということです。10式のXMLを生成できます。NotificationsExtensions.Win10これを使った例としては以下のようなもの。この中でインタラクティブな機能はToastActionCustomの部分にあります。InputsのToastTextBoxでテキストボックスを指定し、そのコンストラクタ―でidとして埋め込まれる文字列を決めています。このidがユーザーからの反応を受け取るときに意味を持ちます。ButtonsのToastButtonでボタンを指定し、そのコンストラクタ―のcontentでボタンに表示される文字列を与え、同時にargumentsとして埋め込まれる文字列を決めています。これで生成されたXMLが以下。先頭のヘッダーはなくても構いません。actionsの部分を見ると、inputが上のInputsに、actionが上のButtonsに対応しています。これぐらいならたいした長さのXMLでもないので、アプリ内に文字列として持っておいて、変わる部分を実行時に嵌め込む方が早いかもしれません。これを使ってトーストを出すとこうなります。ユーザーの反応を受け取るこのトーストにユーザーが反応するとINotificationActivationCallbackのActivateメソッドが実行されます。この引数から型変換を経て得られる情報は以下のとおり。dataの配列の長さしたがって、invokedArgsを見ることでどのボタンが押されたか、dataを見ることでどのテキストボックスに何が入力されていたか判別できるわけです。トーストの下半分のactions部分は地の部分を押しても反応しませんが、上半分のvisual部分は従来のトーストと同様に地の部分を押しただけでも反応し、その場合はinvokedArgsには何も返ってきません。この例でIgnoreとしているボタンはactivationTypeに何も指定していないので、押しても何も起こらず、トーストが消えるだけです。具体例はレポジトリのサンプル(WPF)を見てください。まとめ以上のようにインタラクティブなトースト自体はさほど難しくはないですが、実際にどう利用するかというと、トーストはユーザーが出さないよう設定できるので、これだけにルートを頼れない。トーストからできることと、アプリ本体からできることをよく整理しないと、ユーザーに余分な学習コストがかかる。複雑なことはアプリ本体を呼び出してから行った方が、たぶんコストがかからない。いう問題があるので、あまり凝らずにシンプルな方がいいのかなと思います。通り過ぎていくのが本来の通知ですし。10ではユーザーへの通知インターフェイスとしてアクションセンターが中心に位置づけられています。8式のデスクトップアプリからのトースト通知では十分対応できませんが、対応方法のサンプルがMicrosoftから公開されていたので、整理してみます。言語はC#で、トースト内のインタラクティブ機能については別途。概要まず基本情報とサンプル(C++とC#)は以下のとおり。10WindowsNotifications/desktop-toastsトーストがアクションセンターに対応すると以下のメリットがあります。トーストがタイムアウトなどで消えた後もアクションセンターに残るので、後から見てアクティベートできる。トーストを出したアプリが終了した後でも、トーストからアプリを直接起動して処理を続けることができる。8式のトーストでもトーストが出ている間にアクションセンターを開くとアクションセンターに移動しますが、ただ移動するだけのようです。これらの機能はトーストの設定によってではなく、アプリでCOMのINotificationActivationCallbackインターフェイスを実装したクラスを使って行います。いうより、UWP用に用意された機能を(ラップした関数は提供されないので)剥き出しで使っちゃいなよという感じ。INotificationActivationCallbackのメンバーはActivateメソッドだけで、トーストがアクティベートされるとこのメソッドが実行されます。下準備として、INotificationActivationCallbackを実装したCOMクラスのCLSIDをアプリのショートカットに含める。そのクラスの型をCOMに登録すると、トーストがアクションセンターに残るようになる。そのクラスのCLSIDとアプリの実行ファイルのパスをレジストリに登録してCOMサーバーで起動できるようにすると、トーストからアプリを起動できるようになる。トーストからアプリを起動できるようにする場合、アプリ本体のUIを開く前にバックグラウンドで処理を分岐させたり、アプリ終了時の状態を復元させたり、UXの観点から色々なやり方があると思います。元々のToastNotificationクラスのイベントも発生するので、両方をうまく組み合わせる必要があります。Activatedの場合だけ捉えるのであれば、INotificationActivationCallbackのActivateは常に実行されるので、こちらだけ処理する手もあります。SDKのpropkey.hにある)。読み書きは型がGuidになる以外はAppUserModelIDの場合と同様にできるので省略。具体的なCOMクラスとしては以下のようなものです(INotificationActivationCallbackの宣言などは省略)。基底クラスとしてNotificationActivatorBaseをライブラリに置き、その派生クラスのNotificationActivatorをアプリ本体に置く想定です。これはこのクラスのCLSIDはアプリごとに一意である必要があるため。アプリの起動時にNotificationActivatorの型を引数としてRegisterComTypeメソッドを実行し、COMに登録します。終了時にはUnregisterComTypeメソッドで登録を解除します。トーストがアクティベートされるとActivateメソッドが実行され、RegisterComTypeの引数で与えられていたActionが実行されます。Activateの引数のinvokedArgsとdataはインタラクティブなトーストから返ってくる情報ですが、必要がなければ無視していいです。次に、アプリをCOMサーバーで起動できるようにレジストリに登録するヘルパークラス。これは普通にレジストリを読み書きするだけです。アプリの初回起動時にRegisterComServerを実行します。引数はCOMクラスの型と実行ファイルのパス、起動時のコマンドライン引数(もしあれば)。このレジストリのキーはアプリを使わなくなれば当然不要になるので、削除を。INotificationActivationCallbackの動作は、アプリが実行中に(アクションセンター内に限らず)トーストがアクティベートされると、そのままActivateが実行されます。アプリが終了後にアクティベートされると、レジストリの情報に従ってアプリが起動された後にActivateが実行されます。その際、アプリのコマンドライン引数に自動的に"-Embedding"が追加されるので、その有無でトーストから起動されたか否か判別できます。細かい実装とサンプル(WPF)はレポジトリを見てください。ToastNotificationのイベントとINotificationActivationCallbackのActivateメソッドのタイミングが分かるようになっています。まとめ以上のように、単に通知を出すのとは違って、アクションセンターへの対応はアプリのライフサイクルに関わってくるので少し大事になります。アクティベート時の状態をどうするかによって動作の練り直しが必要になるかもしれません。10で実行する場合は、WinRTのアセンブリはWindows.winmdではなくWindows.Foundation.UniversalApiContract.winmdの方が適当かなと思って参照しようとしたら、このパスが以前と変わってました。いうのは固定されてないと使いづらいんですけどね。Copyをリリースしました。Copy一言でいうと、コードブロック単位のTrimStart(行頭の空白削除)付きのコピーです。以下の二種類のコピーができます。indent)では行頭の空白(スペース、タブ等)を全削除します。indent)では行頭の空白を固定幅に調整します(元の幅が大きければ削除し、小さければ挿入する)。行頭のタブはスペースに置換します。Studioで書いたコードをMarkdown等にコピーする場面がありますが、このときに行頭の余分な空白は無駄だし、見映えも悪いしで削除したりします。名前空間から始まって、クラス、メソッド、メソッド中のブロックとインデントが深くなるにつれ、その一部を切り出したいときにインデント削除が地味に面倒だったりします。標準のMarkdownだとコードブロック指定は4スペース空けですが、これに合わせて調整するのも同じく。Studioからコピーした時点で処理されてればそういう手間も要らないよね、というのがこの拡張機能です。拡張機能ならではの特長として、自分で選択範囲を行頭や行末にきっちり合わせなくても、自動的に開始行の行頭から終了行の行末までに選択し直してからコピーするので、変にずれたり切れたりすることがありません。Studioのコード補完や整形の効いた快適な環境でコードを書いた後の、MarkdownやStackOverflow用の整形が割と億劫だったのですが、これを使えば一発ですし、後から一部修正しても全部コピーし直せばいいので楽です。具体例を挙げると、以下は拡張機能からユーザーのタブサイズ設定を取得するクラスです。indent)したものがこれ。たいしたことはしてませんが、こういうものが一発で出るとMarkdown書きの面倒さが緩和されます。Markdown等へのコピーでフラストレーションを感じていれば試してみてください。プログラミング2016/01/01UniRxでUnityWebRequestUnityのWWWに代わる新しいUnityWebRequestが5.3で実プラットフォームで使えるようになったので、いつもの如くRxにしようとしたら、まだUniRxにラップしたクラスがなかったので、勉強がてら作ってみました。ObservableWebRequestといっても、neueccさんご本人がIssueを立てられているので、公式でもすぐサポートされると思いますが、そこはそれ。流れとしては、UniRxにはCoroutineをObservableに変換するObservable.FromCoroutineがあるので、UnityWebRequestオブジェクトをいい感じにCoroutineにして、これをObservableに変換します。いうか、ObservableWWWをベースにUnityWebRequestに合わせて修正したものを、UnityWebRequestのメソッドと引数に合わせてラップしていくだけです。UnityWebRequestの基本的なCoroutineはこんな感じです。returnで待ち、結果をisErrorプロパティで判別して、成功ならdownloadHandlerプロパティにアタッチされているDownloadHandlerへの参照が入っているので(ファクトリーメソッドによる)、ここからダウンロードされたものを取得します。ファクトリーメソッドはGetのほか、Post、Put、Delete、HeadでRESTをカバーしていて、基本のGet以外にTexture用のGetTextureとAssetBundle用のGetAssetBundleもあります。実行はすべてSendで行われ、WWWのようにコンストラクト即実行とは違います。これに引っ掛かって少し悩みました。これと同じことを、作成したObservableWebRequestでやるとこんな感じです。ObservableWWWとクラス名が違うだけでした。基本的なテストは基本のGetで確認しましたが、他はこれからです。いっても、UnityWebRequestは標準で使う限りシンプルなので、間違える要素は少ないと思いますが。Communitywww.flickr.comコメントについてコメントは承認制です。承認まで時間がかかるときがあります。感想、間違いの指摘など歓迎します。間違いについては、その場所と内容を明記してください。エントリと関係がないもの、不適当と思われるものは承認しません。プロフィールEMOGitHub詳しくないプロフィール当てにならないカスタマイズ。