かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Visual Studio 2010のWPF/Silverlightデザイナの基本的な使い方

見た目が凝ってるものはExpression Blendで!!という感じに言われているせいか、Visual StudioWPF/Silverlightデザイナがいまいち注目を浴びてないような気がしてる今日この頃です。

XAMLは手書きが一番です(キリッ)と私も前は思ってた派なのですが、最近はVisual Studioのデザイナを使えるだけ使って、どうしても手書きのほうが楽なところは手書きでやって、Styleやアニメーション、VisualStateなどを凝りたいときはBlendを使うといった使い方に落ち着いています。ということで、簡単な画面の作成を通して、Visual Studioのデザイナがどれだけ出来る子なのかということを紹介してみたいと思います。

作成する画面

今回作成する画面は、以下のような簡単な入力用画面です。

一応ViewModelがあってTextBoxやButtonはバインドも設定しています。では、簡単に作成の流をおっていきます。

レイアウトをざくっと決める

まずはウィンドウの初期状態から。

Expression Blendのデザイナもそうですが、Visual Stduioのデザイナは、Gridコントロールに対してRowDefinitionやColumnDefinitionを視覚的に作成することが出来るようになっています。以下のようにGridを選択したときに左と上に出てくる青い部分にマウスカーソルをもっていくとGridを区切れるようなラインが表示されます。この状態でクリックするとRowDefinitionやColumnDefinitionが作成されます。

ここでは、以下のように最終目標の画面にあうような数だけの仕切りをざっくりと切りました。最初はこれくらいおおざっぱに切るのが個人的に好きです。

コントロールもざくっと置く

次に、コントロールを配置していきます。LabelとTextBoxとStackPanelの上にButtonを2つといった感じです。LabelやTextBoxなどは複数個置くことになりますが、このときツールボックスで選択する時からCtrlキーを押しっぱなしにしておくとCtrlキーを離すまで同じコントロールを連続で置くことができます。
ということで、以下のようにざくっと置きました。重要なのは、最終的に置きたいGridのマス目内に配置するということです。これさえ守れば大きさは別にどんなのでもかまいません。

Marginの設定を消す

Visual Studioのデザイナで物を置くと、Marginを指定して場所を制御するXAMLが生成されます。個人的にはこのMarginが邪魔なので消してしまいます。消し方は簡単。コントロールを選択して「レイアウトのリセット」→「すべて」を選択します。このとき事前にCtrl+クリックでMarginを消したいコントロールを全て選択しておくと楽です。

レイアウトをリセットするとMarginの設定が消えて、以下のようにGridのマス目いっぱいにコントロールがひろがります。

RowDefinitionとColumnDefinitionの調整

次に、最初に適当に大きさを切っていたGridのRowDefinitionやColumnDefinitionの大きさを調整します。これは、わかりにくいですが、以下のようにGridの左と上にある青い部分にマウスカーソルを持っていくことで表示されます。


上(左)から順番に固定幅、相対幅、自動になります。ColumnDefinitionやRowDefinitionで数字を直接指定するものが固定幅で、12*のように*をつけて指定するものが相対幅でAutoが自動になります。

今回のレイアウトでは左から順にAuto, 固定, 相対幅。上から順番にAuto, 固定, Auto, Autoにします。

そして、固定幅にした部分の幅を5にします。デザイナでGridを選択して画面下部にあるパンくずリストのような部分の▼印をクリックすると、その下にあるコントロールを選択できます。その中にColumnDefinitionsがあるのでそれを選択します。

ColumnDefinitionsの次に同じ要領でColumnDefinitionを選択します。ここでは2つ目の列の定義を設定したいので上から2つ目を選択します。そうするとColumnDefinitionが選択状態になるのでプロパティエディタでWidthを設定します。

同じ要領で上から2つ目のRowDefinitionのHeightも5に設定します。
ただし、ここに限っていえば「それXAMLで直接値いじったほうが早くね?」と思うので自分的にはXAMLいじっちゃうことも多々あります。

各種プロパティの設定

次にLabelのContentを設定します。これはLabelを選択してContentプロパティを追加するだけなので、簡単ですね。

StackPanelのOrientationもHorizontalに設定します。これはドロップダウンからの選択なので間違えなくていいです。

次にボタンを右寄せにしたいのでStackPanelのHorizontalAlignmentをRightに設定します。このとき、たくさんのプロパティから目的のプロパティを探すのが大変なときがあります。そんなときはプロパティエディタの検索と書いてある所にプロパティ名を入れると絞り込んでくれます。

プロパティ名は、部分一致でも検索にひっかけてくれるのでうろ覚えでも安心ですね。

StackPanel上のButtonの間隔はButtonのMarginを2.5にします。これはButtonを2つ選択してプロパティエディタでMarginを設定します。

ButtonのContentもOKとCancelに設定します。これは、画像を示すほどではないので割愛します。

Bindingの設定

だいたい見た目が出来たのでViewModelとのBindingをやっていきます。DataContextの型をデザイナが認識できれば、プロパティエディタから、かなり快適にBindingを指定できます。
ということで、普通あまりしないかもしれませんがApp.xamlのResourcesに以下のようなViewModelクラスを追加します。

namespace DesignerDemo
{
    using System.Windows.Input;

    public class MainViewModel
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public ICommand OKCommand { get; set; }
        public ICommand CancelCommand { get; set; }
    }
}
<Application x:Class="DesignerDemo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:l="clr-namespace:DesignerDemo"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <l:MainViewModel x:Key="MainViewModel" />
    </Application.Resources>
</Application>

では、Windowを選択したプロパティエディタのDataContextにViewModelを設定します。これはXAMLで書くと{StaticResource Key="MainViewModel"}になります。デザイナからやるにはDataContextプロパティ選択して「データバインドの適用...」をクリックします。

そうすると、データバインディングを設定できる画面が開きます。

ソースを選択します。ソースは今回はStaticResourceなので、それを選択します。そうすると、どこのリソースを選択するかを選びます。ここではApplication.Resourcesを選びます。そすうると、その中に定義されているリソースが表示されるのでMainViewModelを選択します。

そうすると、いい感じにDataContextにBindingが設定されます。

DataContext="{Binding Source={StaticResource MainViewModel}}"

次はTextBoxのTextプロパティです。ここにはNameプロパティとAgeプロパティを設定します。DataContextが設定されている場合は最初からパスを選択する画面が表示されます。ここにDataContextのプロパティが表示されるので、目的のプロパティを選択します。

さらに、TextBoxのテキストが変更される度にViewModelのプロパティに値を設定したいのでUpdateSourceTriggerにPropertyChangedを設定します。これもデータバインドを設定する画面のオプションの部分で設定できます。Bindingで設定できる基本的なオプションは設定できるので、この画面は便利で重宝してます。

Windowの微調整

仕上げにWindowのWidthとHeightをリセットしてデフォルト値にします。

SizeToContentをWidthAndHeightに設定します。

完成

ということで以上で完成です。XAMLは以下のような感じになってます。

<Window x:Class="DesignerDemo.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="300" DataContext="{Binding Source={StaticResource MainViewModel}}" SizeToContent="WidthAndHeight">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="5" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="5" />
            <ColumnDefinition Width="163*" />
        </Grid.ColumnDefinitions>
        <Label Content="名前:" Name="label1" />
        <Label Content="年齢:" Grid.Row="2" Name="label2" />
        <TextBox Grid.Column="2" Name="textBox1" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Grid.Column="2" Grid.Row="2" Name="textBox2" Text="{Binding Path=Age, UpdateSourceTrigger=PropertyChanged}" />
        <StackPanel Grid.ColumnSpan="3" Grid.Row="3" Name="stackPanel1" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="OK" Height="23" Name="button1" Width="75" Margin="2.5" />
            <Button Content="Cancel" Height="23" Name="button2" Width="75" Margin="2.5" />
        </StackPanel>
    </Grid>
</Window>

手書きと違うのは、1つのタグが1行に書かれるため横長になってしまう点と、コントロールにNameがついてるところでしょうか。

まとめ

ということでVisual Stduioのデザイナを使って画面を作ってみました。うまく使うことでXAMLを手書きするよりもタイプミスも減っていい感じになると個人的には思っています。
あと、Visual Studioのデザイナの使い方でお勧めなのは、@ITの以下の記事です。

では、快適なXAMLライフを!