VS2012を使ってXAMLをデザイン!その2

CADとかGUIデザインアプリでよくある4隅にハンドルのあるリサイズと移動をさせるためのフレームをユーザーコントロールを使ってデザインする。
再集計のイメージは↓これ

現時点では↓ここまで

左上と右下隅にハンドルがあるだけ。
つまり左上(0, 0)と右下(2,2)があるんで、左下(2,0)と右上(0,2)を追加する。

次はハンドルの幅の枠線に取り掛かる。
で、これの実現方法っていろいろあると思うんやけど

  • 要素の構成はシンプルやけどzオーダー(奥行)の考えがいるパターン(順序依存)
  • 要素の構成は複雑やけど単純なパターン(順序非依存)

実際問題どっちが良いんやろね?俺っちなら下のやり方をおすすめするかも。
まあ、ちょっと脱線するけどzオーダーの話をちょっと書いてみる。
zオーダー(奥行)ってどういう話かって言うと、画面の縦と横(XY軸)以外に画面の前後に対して順番を決めるって考え方で、ざっくり言えば図形同士の重なりをどう解決するかって話なのな。
3D CGとかでペインターズアルゴリズムとかって言って、油絵具で絵を描くように先に書いた下絵の上に色を重ねると後で書いた方が残る仕組みで重なりを解決してる。
なので、奥行が大きい奴から順番に書いていくときちんと重なりが解決される。って単純な仕組み。

実際の例で行こう。論より証拠。百聞は一見に如かず。
左上隅(Row=0,Col=0)から始まって、水平方向に3マスぶち抜き(Grid.ColumnSpan=3)の灰色のバンド

↑こんな感じ。

で、それをXAML上で書く場所を入れ替える。

さっきは消えてた左上と右上のハンドルが見えてる。

灰色のバンドを書いて、隅のハンドルを描くか、隅のハンドルを描いて灰色のバンドで上から塗りつぶすかの違いがXAML上での出現順(zオーダー)で変化する。

  • 要素の構成はシンプルやけどzオーダー(奥行)の考えがいるパターン(順序依存)

ということ。
この場合の順序依存は単にハンドルを後でまとめて描けば良いだけなんで構成のシンプルなこっちで説明してみる。

というか、そのまま左、右、下のバンドを作る。


実行結果。
ここまでのコードは
ShapeFrame.xml

<UserControl x:Class="RxDragDrop.ShapeFrame"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="15"/>
            <RowDefinition Height="300*"/>
            <RowDefinition Height="15"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="15"/>
            <ColumnDefinition Width="300*"/>
            <ColumnDefinition Width="15"/>
        </Grid.ColumnDefinitions>
        <Rectangle Grid.ColumnSpan="3" Fill="#FFE2E2E2" Stroke="Black"/>
        <Rectangle Grid.ColumnSpan="3" Fill="#FFE2E2E2" Stroke="Black" Grid.Row="2"/>
        <Rectangle Grid.RowSpan="3" Fill="#FFE2E2E2" Stroke="Black"/>
        <Rectangle Grid.RowSpan="3" Fill="#FFE2E2E2" Stroke="Black" Grid.Column="2"/>

        <Rectangle Fill="#FFF4F4F5" Stroke="Black"/>
        <Rectangle Fill="Green" Stroke="Black" Grid.Row="2" Grid.Column="0"/>
        <Rectangle Fill="Blue" Stroke="Black" Grid.Row="0" Grid.Column="2"/>
        <Rectangle Fill="Red" Stroke="Black" Grid.Row="2" Grid.Column="2"/>
    </Grid>
</UserControl>

だいぶ出来ましたね。

後は、水平方向と垂直方向にしか動かせないセンターのハンドルを4個つけるだけ。
例によって、親のグリッドが選ばれている状態でツールボックス上でRectangleをダブルクリックして野生のRectangleを召喚します。

元気いっぱいはみ出してますねえ。順序依存なので、挿入される位置には注意してください。
位置が問題なければ、再びRectangleのプロパティのレイアウトブロックで設定します。

野生のプロパティは↑こんな感じ。それをいくつか調整します。

すると↓こんな見た目に。

ハンドルのサイズは縦横固定の15pxにしています。それと同じ値を幅に即値で設定します。
・・・で、ここで即値を書くなんてなるべくなら避けたいってDRY主義者の人もいるかと思います。私もどっちかっつーとそっち派閥。保守性大事。

そういうときはBindingってのを使います。
理屈で言えば、同じ意味の値をそのままコピーする(値を参照する)ってことで、今回は手抜きして自分自身の高さが自動で決まるのを利用して、その値を参照します。

Width="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}"

Width属性に自分自身(Self)のActualHeightの値を設定するって意味です。ちょっとオエってなりますよね?そこまでする?って感じ。
そんな時こそVS2012の出番です。ぶっちゃけ上の設定も式ビルダみたいので自動生成なんです。
まず対象プロパティの右横の小さいボックスをクリック

次に飛び出したメニューからデータバインドの作成

バインドの種類を選んで

パスを選べば完了

で、バインディングはともかくハンドルをそれぞれ同じように作ると。

後何が必要でしょうか?UXを高めるためにはハンドルがハンドルたる機能を備えているとユーザーにフィードバックしたいですよね。
そう、カーソルの形状を変更しましょう。
まずは右下のサイズ変更用ハンドルから。

ハンドルを選択して、プロパティのカーソルを決める。

それで実行してみると。

こんな感じ。その他のハンドルにもそれぞれのカーソルを設定する。
最後にハンドルの色がカラフルなのを黒に戻して出来上がりがこんな感じ。

ハンドル付フレームのユーザーコントロールをVS2012でデザインするはこれにて終了。
実際に機能するようにするのは結構頑張らないとね。