2015/07/27

VisualStateManagerのVisualStateを確認する

WPFのコントロールの遷移をVisualStateManagerでデザインしていると、現在のVisualStateを直接確認したいときがあります。

VisualStateGroupが一つだけなら同じVisualStateGroup内のVisualStateは排他なので結果を見て判断することも難しくないですが、VisualStateGroupが複数になると異なるVisualStateGroup間のVisualStateは併存するので、複数のVisualStateの効果が重なることになり、何がどうなっているか判断に迷うことがあります。というか、かなり迷いました。

そこで、デバッグ用に現在のVisualStateを出力する添付プロパティを書いてみました。
このキモは、VisualStateGroupは対象のコントロール自体ではなく、たいていその中のGridなどに定義されるので、子要素を下りながら探す必要があることです。なお、VisualStateManagerではなくトリガーに依っている場合は、当然何も出てきません。

VisualStateの変化を捉える方法が見つからなかったのでIntervalで指定された秒ごとに永久ループで出力しますが、そこはあくまでデバッグ用ということで。

これをToggleButtonに使った例。
このToggleButtonにはCommonStatesとCheckStatesのVisualStateGroupがあり、これらがToggleButtonと継承元のButtonBaseとさらに元のControlのChangeVisualStateの重ね掛けで変化するというややこしいものですが、一番下に加えたVisualStateMonitorの添付プロパティは以下のように出力します。
// 初期状態
Element: TestToggleButton -> Group: CommonStates -> State: Normal
Element: TestToggleButton -> Group: CheckStates -> State: Unchecked
// カーソルを上に移動
Element: TestToggleButton -> Group: CommonStates -> State: MouseOver
Element: TestToggleButton -> Group: CheckStates -> State: Unchecked
// クリック
Element: TestToggleButton -> Group: CommonStates -> State: MouseOver
Element: TestToggleButton -> Group: CheckStates -> State: Checked
// カーソルを上から外す
Element: TestToggleButton -> Group: CommonStates -> State: Normal
Element: TestToggleButton -> Group: CheckStates -> State: Checked
// 再度クリックしてカーソルを外す
Element: TestToggleButton -> Group: CommonStates -> State: Normal
Element: TestToggleButton -> Group: CheckStates -> State: Unchecked
これが分かれば簡単になるというものでもないですが、直接確認しながら作業できるのは随分違うと思います。実はもっと簡単にできる方法があるのかもしれませんが、とりあえず。

[追記] 添付プロパティの作成について

添付プロパティの構文の話ですが、依存関係プロパティの場合、PropertyMetadataのPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)のdはそのプロパティが定義されたクラスのインスタンスなので、これをキャストして処理をインスタンスメンバーに繋げることができます。一方、添付プロパティの場合、dはそのプロパティが添付されたFrameworkElementのインスタンスになるので、添付プロパティが定義されたクラスのインスタンスメンバーにそのままアクセスはできません。

したがって、FrameworkElementのインスタンスの処理はおおよそ以下に分かれます。
  1. 静的メソッドの中で処理を完結させる。デリゲートを駆使すればある程度複雑なこともできるが、状態をフィールドなどに保存できないので、行き届いた状態管理は難しい。

  2. 静的メソッドの中で、状態を静的フィールドなどに保存しながら処理する。アプリ中の一カ所でしか使われない場合や、静的な値が共有されても構わない場合に限られる。

  3. 添付プロパティの型をそのプロパティが定義されたクラスにすると、初期化時にe.NewValueにそのクラスのインスタンスが入ってくるので、それをキャストしてインスタンスメンバーに繋げる。WindowChromeで使われている方法で、複雑な処理も行いやすい。
あくまで構文上のテクニックですが、結構悩むところなので。

2015/06/25

OneDriveとデスクトップアプリ

OneDriveをWindows 8.1に同期して使っているとき、OneDrive中のファイルをデスクトップアプリから扱う方法に関して。

1. オンラインのみのファイルの判別


Windows 8.1ではOneDrive中のファイルを「オフラインで利用可能」か「オンラインのみ」に設定できるが、「オンラインのみ」にした場合、これをデスクトップアプリのSystem.IO.FileStreamで開こうとすると、例外(System.IO.IOException)が飛ぶ。

例えば、以下のうち下の利用可能性を「オンラインのみ」にしたファイルがそれに当たる。


同じフォルダをコマンドプロンプトから「dir /a」で表示させたもの。「オンラインのみ」のファイルはサイズが括弧で囲まれている。


「オンラインのみ」のファイルはファイルエントリだけがローカルにあって、データ本体はクラウド上にあるものが必要に応じて流れてくるものなので、その状態では開けないのは別に不思議ではない。

問題はそれを事前にどうやって判別するかで、WinRTではStorageFile.IsAvailableかStorageFile.AttributesのLocallyIncompleteを見ればいい。一方、デスクトップアプリではそのものずばりの情報が出てこなくて時間を取られたが、答えは簡単だった。
このファイル属性のうち、Oのオフライン属性がそれで、OneDriveで「オンラインのみ」のファイルにはこれが付く。System.IO.FileAttributesのOfflineの項を見ると、"The file is offline. The data of the file is not immediately available."とあるので(OneDriveとは一言も出てこないが)、これらしい。

ということで、以下はテストコードとその結果。
見ての通り、「オンラインのみ」のファイルかどうかはオフライン属性の有無で判別できることが確認できる(オンラインとオフラインの用語がややこしい)。ちなみに、これらのファイルに付いている属性は、初めにエクスプローラーで属性を表示させたものと当然ながら一致している。

2. オンラインのみのファイルへのアクセス


オーソドックスにはOneDriveのAPIを使えばいい話だが、MSDNに以下のエントリがあった。
このサンプルコードをふむふむと読み始めて、途中で意味が呑み込めてきて……驚愕。

デスクトップアプリからWinRTのAPIを使うお約束をすっ飛ばし、デスクトップアプリでも使えるとされていないStorageFileクラスを、WinRTのアセンブリを動的ロードしてリフレクションして実行するラッパー、とは!

いや、Microsoftの人が書いているのだからできるのだろうが、何という力業。積極的に使いたいかは別にして、そういうのもあるのか……と。

3. Windows 10での変更


Windows 10ではまたOneDriveに変更があるらしく、現在のInsider Previewでは「オンラインのみ」の設定はなくなり、すべて「オフラインで利用可能」と同じく、データ本体がローカルにコピーされるようになっている。したがって、「オンラインのみ」のファイルを扱う方法はWindows 8.1で最後になるらしい。いい加減安定させた方がいいと思うが。

2015/06/20

水晶雫グラフィグ

水晶雫ちゃんの3回目の誕生日に合わせて、イラストレーターの桐野霞先生が水晶雫グラフィグを公開されていたので、早速作ってみました。
グラフィグというのは独特の四角いスタイルにデフォルメされた、キャラクターペーパークラフトのフォーマットのようなもの、だと思います。

1. 出来上がり


PDFをキンコーズでプリントアウトしたものから数時間の作業後、完成したお姿。
Suisho Shizuku Graphig

カラーレーザープリンターによる出力ということで、印刷物と変わらない美麗さでした。
Suisho Shizuku Graphig

グラフィグなので、とくに後ろから見ると箱箱しています。
Suisho Shizuku Graphig

首は回せるので、少し動きは付けられます。
Suisho Shizuku Graphig

これだけデフォルメしても雫ちゃんのイメージは保たれているのはさすがです。部品を作っている間はカクカクしてるなと思っていたのが、全部合わせた途端、なるほどなるほど、これはこれで、と顕現する感じです。

2. 参考


作り方に複雑なことはないですが、参考になりそうなことを。
  • キンコーズでの出力は、マットで210g/m2ぐらいの紙を使用。強度的には厚い方がいいですが、厚すぎると狙った位置できれいに折るのが難しくなります。結果的にはこれ以上厚いと難しくなる感じ。費用は、PC利用を除いたプリントアウトだけだと一枚50円強で、1セット2枚で100円強でした。一応、ミスに備えて予備の分もプリントアウトしておくとベター(自分は使った)。

  • 頭部の頬の部分の折り線が少しズレてるので、先に顎の部分を折り、机の角で箱に組みながら折る位置を順々に出していくといいです。この際、差し込むベロの部分は切り落として、のりしろと接着剤だけで固定するようにした方が調整はしやすいです。ただ、頭の側面は髪ですっぽり隠れるので、あまり神経質になる必要はないです。

  • 足の上下をぴったり接着したら、上下の長さが少し違っていて切り込まないといけなくなったので、仮組みをよくやった方がいいです。
まあしかし、手軽にできるのがペーパークラフトのいいところだと思うので、あくまで気楽にどうぞ。