読者です 読者をやめる 読者になる 読者になる

画面のほとんどを XAML を記述せずに作成してみた

ここのところ XAML ばかり記述しているので、
気分を変えて全てコードで記述してみました。

まず完成した画面から。
f:id:griefworker:20081027101209p:image

そしてソースコードは次の通り。

/// <summary>
/// Window1.xaml の相互作用ロジック
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        Width = 400;
        Height = 350;
        Background = new SolidColorBrush(Color.FromRgb(48, 48, 48));

        // Label 用の Style を追加
        Style labelStyle = new Style(typeof(Label));
        labelStyle.Setters.Add(new Setter(Label.ForegroundProperty, new SolidColorBrush(Color.FromRgb(240, 240, 240))));
        Resources.Add(typeof(Label), labelStyle);

        // TextBox 用の Style を追加
        Style textBoxStyle = new Style(typeof(TextBox));
        textBoxStyle.Setters.Add(new Setter(TextBox.ForegroundProperty, new SolidColorBrush(Color.FromRgb(240, 240, 240))));
        textBoxStyle.Setters.Add(new Setter(TextBox.BackgroundProperty, new SolidColorBrush(Color.FromRgb(68, 68, 68))));
        textBoxStyle.Setters.Add(new Setter(TextBox.MarginProperty, new Thickness(2)));
        textBoxStyle.Setters.Add(new Setter(TextBox.HeightProperty, (double)28));
        Resources.Add(typeof(TextBox), textBoxStyle);

        // ComboBox 用の Style を追加
        Style comboBoxStyle = new Style(typeof(ComboBox));
        comboBoxStyle.Setters.Add(new Setter(ComboBox.ForegroundProperty, new SolidColorBrush(Color.FromRgb(240, 240, 240))));
        comboBoxStyle.Setters.Add(new Setter(ComboBox.BackgroundProperty, new SolidColorBrush(Color.FromRgb(68, 68, 68))));
        comboBoxStyle.Setters.Add(new Setter(ComboBox.MarginProperty, new Thickness(2)));
        comboBoxStyle.Setters.Add(new Setter(ComboBox.HeightProperty, (double)28));
        Resources.Add(typeof(ComboBox), comboBoxStyle);

        // Button 用の Style を追加
        Style buttonStyle = new Style(typeof(Button));
        buttonStyle.Setters.Add(new Setter(Button.ForegroundProperty, new SolidColorBrush(Color.FromRgb(240, 240, 240))));
        buttonStyle.Setters.Add(new Setter(Button.BackgroundProperty, new SolidColorBrush(Color.FromRgb(5, 147, 14 * 16 + 2))));
        buttonStyle.Setters.Add(new Setter(Button.HeightProperty, (double)28));
        buttonStyle.Setters.Add(new Setter(Button.MarginProperty, new Thickness(1)));
        Resources.Add(typeof(Button), buttonStyle);

        // 一番外側の DockPanel を追加
        DockPanel dockPanel = new DockPanel();
        Content = dockPanel;

        // [OK][キャンセル] を置く StackPanel を作成
        StackPanel stackPanel = new StackPanel();
        stackPanel.Orientation = Orientation.Horizontal;
        stackPanel.FlowDirection = FlowDirection.RightToLeft;

        // StackPanel にボタンを追加
        stackPanel.Children.Add(new Button() { Content = "キャンセル", Width = 90 });
        stackPanel.Children.Add(new Button() { Content = "OK", Width = 90 });

        // StackPanel を追加
        dockPanel.Children.Add(stackPanel);
        DockPanel.SetDock(stackPanel, Dock.Bottom);

        // 入力欄を置く Grid を作成
        Grid grid = new Grid();
        grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(120) });
        grid.ColumnDefinitions.Add(new ColumnDefinition());
        grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(50) });
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions.Add(new RowDefinition());

        // Grid にラベルを追加
        grid.AddChild(new Label() { Content = "名前" }, 0, 0, 1, 1);
        grid.AddChild(new Label() { Content = "ファイル名" }, 1, 0, 1, 1);
        grid.AddChild(new Label() { Content = "パラメータ" }, 2, 0, 1, 1);
        grid.AddChild(new Label() { Content = "作業フォルダ" }, 3, 0, 1, 1);
        grid.AddChild(new Label() { Content = "実行時の大きさ" }, 4, 0, 1, 1);
        grid.AddChild(new Label() { Content = "ツールチップ" }, 5, 0, 1, 1);
        grid.AddChild(new Label() { Content = "ショートカットキー" }, 6, 0, 1, 1);
        grid.AddChild(new Label() { Content = "ホットキー" }, 7, 0, 1, 1);

        // Grid に TextBox と ComboBox を追加
        grid.AddChild(new TextBox(), 0, 1, 1, 2);
        grid.AddChild(new TextBox(), 1, 1, 1, 1);
        grid.AddChild(new TextBox(), 2, 1, 1, 2);
        grid.AddChild(new TextBox(), 3, 1, 1, 2);
        grid.AddChild(new ComboBox(), 4, 1, 1, 2);
        grid.AddChild(new TextBox(), 5, 1, 1, 2);
        grid.AddChild(new TextBox(), 6, 1, 1, 1);
        grid.AddChild(new TextBox(), 7, 1, 1, 1);

        // Grid に Button を追加
        grid.AddChild(new Button { Content = "参照" }, 1, 2, 1, 1);
        grid.AddChild(new Button { Content = "クリア" }, 6, 2, 1, 1);
        grid.AddChild(new Button { Content = "クリア" }, 7, 2, 1, 1);

        dockPanel.Children.Add(grid);
        DockPanel.SetDock(grid, Dock.Top);
    }
}

// ちょっと楽をするために拡張メソッドを用意
public static class GridExtensions
{
    // 行と列を指定してコントロールを追加する
    public static Grid AddChild(this Grid grid, UIElement element, int rowIndex, int columnIndex, int rowSpan, int columnSpan)
    {
        if (rowSpan < 1)
        {
            throw new ArgumentOutOfRangeException("rowSpan");
        }
        if (columnSpan < 1)
        {
            throw new ArgumentOutOfRangeException("columnSpan");
        }

        // Grid に追加
        grid.Children.Add(element);

        // 位置を指定
        Grid.SetRow(element, rowIndex);
        Grid.SetColumn(element, columnIndex);

        // セルを結合
        Grid.SetRowSpan(element, rowSpan);
        Grid.SetColumnSpan(element, columnSpan);

        return grid;
    }
}

Grid に追加したコントロールの位置を指定するのに手間取りました。添付プロパティを設定するためのスタティックメソッドが用意されていたとは。これは見落とし易いかも(私だけ?)。

あと、書いてるうちにすごく面倒になってきましたw画面は XAML で記述すべきですね。でもコードで動的に生成しなければいけない場面もあるか・・・。パッケージソフトとか。