Thumb コントロールで Photoshop のナビゲーターを再現する

@kurosawa0626 さんが Photoshop のナビゲーター的なものを作りたい、という話をしていて、過去に似たようなものを作ったことがあったので共有してみます。
記事内のコードは WPF で書いたものですが、WinRT でも一部を除いてほぼ同じようなコードで書けるはずです。

2015/04/12 追記:
@okazuki さんが、WinRT でやる場合の補足記事を書いてくださいました。
http://okazuki.hatenablog.com/entry/2015/04/11/195941

目標

今回は、Thumb コントロールを活用し、Photoshop のナビゲーターと同等のものを作ります。
ScrollViewer に表示されているコンテンツについて、以下を実現しましょう。

  • サムネイルの表示
  • Viewport (赤枠部分) の表示
  • 赤枠のドラッグで Viewport の位置変更

↓ みたいなやつ

Photoshop

最終的に完成したコードは、gist で公開しています。
WPF アプリケーションを作成し、MainWindow.xaml と MainWindow.xaml.cs を組み込めば実行できます。

ScrollViewer とか

大きなコンテンツを画面内に収めたいときは、ScrollViewer コントロールを使用しましょう。
表示領域よりもコンテンツのサイズの方が大きいとき、ScrollViewer はスクロール バーを表示して、可視領域を移動できるようになります。

このとき、実際に見えている領域のことを Viewport と呼びます。
それに対し、ScrollViewer 内の全域 (= コンテンツのサイズ) は Extent です。
それぞれ、ViewportWidth、ViewportHeight、ExtentWidth、ExtentHeight プロパティでサイズを取得できます。

余談ですが、ListBox などの ItemsControl 派生型は、内部で ScrollViewer を使用していることが多いですね。

ScrollViewer (WPF)
ScrollViewer (WinRT)

ひとまず、下記のように画像 (line 28-34) とサムネイル (line 19-21)、そして Viewport を示す Border (line 22-25) 配置する XAML コードを用意しました。

サムネイルと Viewport の表示

Bitmap

コンテンツ部分の Visual 要素をビットマップに書き込み、画像として表示する方法です。
WPF と WinRT でやり方が微妙に異なりますが、考え方は同じです。

VisualBrush (WPF のみ)

別の方法もあります。
Brush 派生型の VisualBrush を使用し、コンテンツ部分の Visual 要素でサムネイル領域を塗りつぶすことで、縮小されたサムネイルを表現できます。
残念ながら WinRT には VisualBrush がないため、WPF 限定です。

Viewport

サムネイル上に ScrollViewer が表示している範囲 (Viewport) を示すためには、…手計算です! (説明省略

この時点で、ScrollViewer 内に画像を表示し、画像のサムネイルを表示し、更に ScrollViewer で実際に見えている範囲を赤枠で表示することができました。

sample

CombinedGeometry

これは、WPF 限定です。

サムネイルと同じサイズの図形と、Viewport (赤枠) 部分と同じサイズの図形を、それぞれ RectangleGeometry で表現し、それを CombinedGeometry で結合させます。
その際、GeometryCombineMode=”Xor” を指定することによって、「Viewport 以外の部分のみを塗りつぶす」ことが可能です。

方法 : 結合したジオメトリを作成する
https://msdn.microsoft.com/ja-jp/library/ms746682(v=vs.110).aspx

sample2

Thumb コントロール

今回のミソである Viewport (赤枠) を、サムネイル上で動かせるようにしましょう。
もっとも簡単な方法は、Thumb コントロールを使用することです。

System.Windows.Controls.Primitives.Thumb (WPF)
Windows.UI.Xaml.Controls.Primitives.Thumb (WinRT)

Thumb コントロールは、ユーザーがドラッグによってコントロールを動かす機能を簡単に実現するためのものです。
これは、ScrollBar や Slider でユーザーがドラッグする部分 (“つまみ” の部分) で使われているものです。

DragStarted、DragCompleted、および DragDelta イベントを使用し、それぞれドラッグの開始と終了、ドラッグの移動量を検知することができます。
今回のサンプルでは、赤枠部分を Thumb コントロールに置き換え、DragDelta イベントを使用し移動量を ScrollViewer に反映します。
Thumb コントロールは他のコントロールと同様に ControlTemplate を使用し外観をカスタマイズできるため、赤枠は Thumb の外観として表現します。

これで完成です!

viewport

まとめ

実は、1 年前に「Primitive コントロール探訪」という形で Controls.Primitives 名前空間以下の便利コントロールを紹介しようと書きかけていた記事の一つだったりします (忙しくて頓挫してますが!)。

今回は、@kurosawa0626 さんのリクエストで復活しました。
ありがとうございます (?)。

前述のとおり、Thumb コントロールは、ScrollBar や Slider の “つまみ” の部分で利用されているものです。
うまく活用すれば、今回のようにドラッグでコントロールを動かしたい場合や、リサイズ処理等に応用できます。
使ってみてください!

今回のサンプルは、gist で公開しています。
WPF アプリケーションを作成し、MainWindow.xaml と MainWindow.xaml.cs を組み込めば実行できます。
https://gist.github.com/Grabacr07/988bc04fb7f16aaa4fdc

This entry was posted in 未分類. Bookmark the permalink.

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です