rksoftware

Visual Studio とか C# とかが好きです

デザイナがなくても問題なし .NET Core 3.0 で Windows フォームアプリケーションを作る

.NET Core 3.0 で Windows フォームアプリケーションを作るには、.NET Framework と同じようにまずプロジェクト(ソリューション)を作ります。
.NET Core 3.0 用のフォームのデザイナがないことが話題ですが、大丈夫です。対策となる大きく2つの手法をこの記事で書いています。

対策となる2種類の手法

  • コードビハインドで配置する
  • デザイナーが忘れられない!

■ プロジェクトの作成

対策は後述するので、まずはプロジェクトを作成して行きます。

プロジェクト作成コマンド

dotnet new winforms -n winformapp

この例では、 -n でプロジェクト名を winformapp と指定しています。プロジェクト名のフォルダが作られ、その中にプロジェクトが作成されています。
プロジェクトの場所へフォルダを移動します。

cd winformapp

ただ、ここまでの手順ではソリューションは作られていないのでソリューションも作っておきましょう。

ソリューション作成コマンド

dotnet new sln

winformapp.sln ファイルが作成されますが、まだプロジェクトが含まれていないのでプロジェクトをソリューションに追加します。

dotnet sln add winformapp.csproj

これでソリューションに winformapp プロジェクトが追加されました。

作成したソリューションを Visual Studio 2019 Preview で開きます。

  • Visual Studio 2019 Preview を起動します
  • [ プロジェクトやソリューションを開く ] から作成した winformapp.sln を選択します。

■ デバッグ実行

作成した winformapp プロジェクトはそのまま実行可能です。いったん実行してみましょう。 f:id:rksoftware:20190101223611j:plain
ここから色々とコントロールを配置してアプリを作って行くわけですが、残念ながらコントロールを配置するためのデザイナーが用意されていません。
しかし、まだあきらめるタイミングではありません。Windows フォームアプリケーションはデザイナーがなければ作らないというものではありません。

■ パターン1 コードビハインドで配置する

コードビハインドでコントロールを new して配置して行けば簡単にコントロールを配置できます。
Form1.cs にコードを書いていきます。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace winformapp
{
    public partial class Form1 : Form
    {
        // 配置したコントロールを保持するメンバー
        Panel panel;
        TextBox textBox;
        Button button;

        public Form1()
        {
            InitializeComponent();

            // 自分でコントロールを生成し配置する
            CreateAndLayoutControls();
        }

        // 自分でコントロールを生成し配置する
        void CreateAndLayoutControls()
        {
            // パネルを生成し Form の上に乗せる(背景色はアジュール)
            this.Controls.Add(panel = new Panel
            {
                Location = new Point(10, 10),
                BackColor = Color.Azure,
                Size = new Size(300,100),
            });

            // テキストボックスを生成しパネルの上に乗せる
            panel.Controls.Add(textBox = new TextBox
            {
                Location = new Point(5,0),
                Size = new Size(200,22),
            });

            // ボタンを生成しパネルの上に乗せる(背景色はクリムゾン)
            panel.Controls.Add(button = new Button
            {
                Location = new Point(5, 23),
                Size = new Size(200, 22),
                Text = "ボタン",
                BackColor = Color.Crimson,
            });

            // ボタンクリック時のイベントハンドラを設定する
            button.Click += Button_Click;

            // パネルが表示されるよう最前面に移動
            panel.BringToFront();
        }

        // ボタンクリックのイベントハンドラ
        private void Button_Click(object sender, EventArgs e)
        {
            // テキストボックスに入力されている文字列をメッセージボックスで表示
            MessageBox.Show(textBox.Text);
        }

        private void buttonExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}

ポイントは次のパネル生成部分のコードです。

// パネルを生成し Form の上に乗せる(背景色はアジュール)
this.Controls.Add(panel = new Panel
{
    Location = new Point(10, 10),
    BackColor = Color.Azure,
    Size = new Size(300,100),
});

Windows フォームのコントロールは当たり前と言えば当たり前ですが、new してインスタンス化できます。つまり普通に new して Form に Add してやれば画面に表示されます。
あとはこれを配置したいコントロール分繰り返せば OK です。簡単ですね。

他のポイントとしては

// 配置したコントロールを保持するメンバー
Panel panel;
TextBox textBox;
Button button;

というメンバー宣言でしょうか。デザイナーで配置した場合と同じように、コードビハインドでコントロールを操作するためにメンバーにコントロールのインスタンスを保持しています。これはデザイナーで配置した場合もデザイナーが同様のコードを自動で作成してくれているものです。

実行

実行するとこのように、パネルの上にテキストボックスとボタンが置かれ、ボタンクリックのイベントも動作します。
f:id:rksoftware:20190101223634j:plain
f:id:rksoftware:20190101223650j:plain

■ パターン2 デザイナーと同じがいい!

コードでコントロールを配置するのに違和感がありどうしてもデザイナーがいいという方も大丈夫です。Windows フォームアプリケーションのデザイナーが生成するコードはシンプルなので誰でも簡単に書けます。
まずは、テンプレートで生まれたコードを見てみましょう。

namespace winformapp
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.buttonExit = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 28.125F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(800, 376);
            this.label1.TabIndex = 1;
            this.label1.Text = "Hello .NET Core!";
            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // buttonExit
            // 
            this.buttonExit.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.buttonExit.Location = new System.Drawing.Point(0, 376);
            this.buttonExit.Name = "buttonExit";
            this.buttonExit.Size = new System.Drawing.Size(800, 74);
            this.buttonExit.TabIndex = 1;
            this.buttonExit.Text = "E&xit";
            this.buttonExit.UseVisualStyleBackColor = true;
            this.buttonExit.Click += new System.EventHandler(this.buttonExit_Click);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.buttonExit);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Button buttonExit;
    }
}

とても簡単ですね。大きく4つの区切りがあります。

コントロールのインスタンス保持用のメンバー宣言

一番下の部分です。ここでコントロールのインスタンスを保持するメンバーの宣言をしています。コントロールを追加したい場合、まずはここにメンバーを追加すれば良いでしょう。簡単ですね。

private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button buttonExit;

コントロールのインスタンス化

戻ってコードの上の方 InitializeComponent メソッドの最初の部分です。ここで、コントロールのインスタンスを生成しています。コントロールを追加した良い場合、ここでインスタンス化すれば良いでしょう。簡単ですね。

this.label1 = new System.Windows.Forms.Label();
this.buttonExit = new System.Windows.Forms.Button();

コントロールのプロパティ

次の部分はコントロールのプロパティを設定する部分です。コントロール全てのプロパティの初期値を順に設定しています。コントロールのプロパティはここで設定すれば良いでしょう。簡単ですね。

// 
// label1
// 
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 28.125F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(800, 376);
this.label1.TabIndex = 1;
this.label1.Text = "Hello .NET Core!";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;

コントロールの Add

次の部分は Form の設定をしている部分です。Form のプロパティの設定とコントロールの追加をしています。フォームへのコントロールの追加はここで行えばいいでしょう。簡単ですね。

// 
// Form1
// 
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.label1);
this.Controls.Add(this.buttonExit);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

コントロールを配置する

Form1.Designer.cs を編集してコントロールを配置してみます。

namespace winformapp
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.buttonExit = new System.Windows.Forms.Button();
            this.panel = new System.Windows.Forms.Panel();
            this.textBox = new System.Windows.Forms.TextBox();
            this.button = new System.Windows.Forms.Button();
            this.panel.SuspendLayout();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 28.125F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(800, 376);
            this.label1.TabIndex = 1;
            this.label1.Text = "Hello .NET Core!";
            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // buttonExit
            // 
            this.buttonExit.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.buttonExit.Location = new System.Drawing.Point(0, 376);
            this.buttonExit.Name = "buttonExit";
            this.buttonExit.Size = new System.Drawing.Size(800, 74);
            this.buttonExit.TabIndex = 1;
            this.buttonExit.Text = "E&xit";
            this.buttonExit.UseVisualStyleBackColor = true;
            this.buttonExit.Click += new System.EventHandler(this.buttonExit_Click);
            // 
            // panel
            // 
            this.panel.Controls.Add(this.textBox);
            this.panel.Controls.Add(this.button);
            this.panel.BackColor = System.Drawing.Color.Azure;
            this.panel.Location = new System.Drawing.Point(10, 10);
            this.panel.Size = new System.Drawing.Size(300, 100);
            // 
            // textBox
            // 
            this.textBox.Location = new System.Drawing.Point(5, 0);
            this.textBox.Size = new System.Drawing.Size(200, 22);
            // 
            // button
            // 
            this.button.BackColor = System.Drawing.Color.Crimson;
            this.button.Location = new System.Drawing.Point(5, 23);
            this.button.Size = new System.Drawing.Size(200, 22);
            this.button.Text = "ボタン";
            this.button.Click += new System.EventHandler(this.Button_Click);
            // 
            // Form1
            // 
            //this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.panel);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.buttonExit);
            this.Name = "Form1";
            this.Text = "Form1";
            this.panel.ResumeLayout(false);
            this.panel.PerformLayout();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Button buttonExit;
        private System.Windows.Forms.Panel panel;
        private System.Windows.Forms.TextBox textBox;
        private System.Windows.Forms.Button button;
    }
}

こんな感じで書けば、デザイナーなしでもコントロールを配置できます。簡単ですね。
是非チャレンジしてみてください。