1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

カスタムDatePicker:TextBoxを使った便利な日付選択機能の実装

Posted at

はじめに

Windowsフォームアプリケーションで日付を入力する際、デフォルトの日付ピッカー(DateTimePicker)を使用するのが一般的ですが、デザインや機能をカスタマイズしたい場合には適していません。本記事では、TextBox をベースにしたカスタム日付ピッカーの実装方法を紹介します。

本カスタム日付ピッカーでは、以下のような機能を提供します。

  • TextBox 内に日付を表示
  • MonthCalendar をポップアップ表示
  • BackColorをカスタマイズ可能
  • カスタムのカレンダーアイコンを追加可能
  • 初期選択デートやリセット機能の実装

実装方法

1. CustomDatePickerDemo クラスの作成
TextBox を継承して、クリックすると MonthCalendar を表示するカスタム日付ピッカーを作成します。

public class CustomDatePickerDemo : TextBox
{
    private MonthCalendar monthCalendar;
    private Form popupForm;
    private Form parentForm;

    // 選択された日付を取得および設定するための SelectedDate プロパティ
    private DateTime selectedDate = DateTime.Now;

    public DateTime SelectedDate
    {
        get { return selectedDate; }
        set
        {
            selectedDate = value;

            // カレンダーの日付を設定
            if (monthCalendar != null)
            {
                monthCalendar.SetDate(selectedDate);
            }

            // TextBox のテキストを選択された日付で更新
            this.Text = selectedDate.ToString("yyyy年MM月dd日");
        }
    }

    protected override void OnParentChanged(EventArgs e)
    {
        base.OnParentChanged(e);
        if (this.Parent != null)
        {
            parentForm = this.FindForm();
            if (parentForm != null)
            {
                parentForm.MouseDown += ParentForm_MouseDown; // TextBox 外部のクリックを検出
            }
        }
    }

    private void ShowCalendar()
    {
        if (popupForm != null)
        {
            popupForm.Close();
            popupForm = null;
        }

        popupForm = new Form
        {
            FormBorderStyle = FormBorderStyle.None,
            ShowInTaskbar = false,
            StartPosition = FormStartPosition.Manual,
            AutoSize = false,
        };

        monthCalendar = new MonthCalendar
        {
            MaxSelectionCount = 1
        };

        // テキストが空の場合、カレンダーの選択日を現在の日付に設定
        if (string.IsNullOrEmpty(this.Text))
        {
            monthCalendar.SetDate(DateTime.Now);
        }
        else
        {
            // テキストが空でない場合、カレンダーの選択日を現在の SelectedDate に設定
            monthCalendar.SetDate(SelectedDate);
        }

        // カレンダーが表示されたときに選択日を設定
        monthCalendar.DateSelected += MonthCalendar_DateSelected;
        popupForm.Controls.Add(monthCalendar);

        // カレンダーのサイズに基づいてポップアップのサイズを調整
        popupForm.ClientSize = new Size(
            monthCalendar.Width + 48,
            monthCalendar.Height + 6
        );

        // TextBox の下にポップアップを配置
        Point screenLocation = this.PointToScreen(new Point(0, this.Height));
        popupForm.Location = screenLocation;

        popupForm.Deactivate += (s, e) => CloseCalendar();

        popupForm.Show();
    }

    private void MonthCalendar_DateSelected(object sender, DateRangeEventArgs e)
    {
        // カレンダーで日付が選択されたときに、TextBox のテキストを更新
        this.Text = e.Start.ToString("yyyy年MM月dd日");

        // SelectedDate プロパティを更新
        SelectedDate = e.Start;

        CloseCalendar();
        if (parentForm != null)
        {
            parentForm.ActiveControl = null; // TextBox からフォーカスを外す
        }
    }

    private void ParentForm_MouseDown(object sender, MouseEventArgs e)
    {
        if (popupForm == null)
            return;

        Point mousePosition = parentForm.PointToScreen(e.Location);

        if (this.Bounds.Contains(this.Parent.PointToClient(mousePosition)))
            return;

        if (popupForm.Bounds.Contains(mousePosition))
            return;

        // クリックが外部だった場合、カレンダーを閉じる
        CloseCalendar();
    }

    private void CloseCalendar()
    {
        if (popupForm != null)
        {
            popupForm.Close();
            popupForm = null
        }
    }
}

2. BackColorのカスタマイズ
CustomBackColor プロパティを追加することで、TextBox の背景色を変更できます。

public Color CustomBackColor
{
    get { return this.BackColor; }
    set { this.BackColor = value; }
}

3. カレンダーアイコンの追加
カレンダーアイコンを PictureBox で追加し、クリック時に ShowCalendar() を実行することで、より直感的なUIを実現できます。

private PictureBox calendarIcon;
public CustomDatePickerDemo()
{
    calendarIcon = new PictureBox
    {
        Image = Properties.Resources.calendarDark, // 画像リソースを指定
        SizeMode = PictureBoxSizeMode.StretchImage,
        Size = new Size(20, 20),
        Cursor = Cursors.Hand,
        Location = new Point(this.Width + 28, (this.Height - 20) / 2),
        BackColor = Color.Transparent
    };
    this.Controls.Add(calendarIcon);
    calendarIcon.Click += (s, e) => ShowCalendar();
    this.Click += (s, e) => ShowCalendar();

}

4.フォームでの利用
CustomDatePickerDemo をフォームに追加し、複数の TextBox に適用できます。

public partial class CustomDatePickerForm : Form
{
    public CustomDatePickerDemo customDatePicker;

    public CustomDatePickerForm()
    {
        InitializeComponent();

        customDatePicker = new CustomDatePickerDemo
        {
            Location = new Point(45, 20),
            Width = 150,
            CustomBackColor = Color.Yellow
        };
        this.panel1.Controls.Add(customDatePicker);

        CustomDatePickerDemo customDatePicker2 = new CustomDatePickerDemo
        {
            Location = new Point(45, 20),
            Width = 150,
            CustomBackColor = Color.Yellow,
            SelectedDate = new DateTime(2022, 3, 2)
        };
        this.panel2.Controls.Add(customDatePicker2);
    }

    private void btnOk_Click(object sender, EventArgs e)
    {
        MessageBox.Show(customDatePicker.SelectedDate.ToString("yyyy年MM月dd日"));
    }
}

5. リセット機能の実装
リセットボタンをクリックすると、TextBox の内容をクリアし、カレンダーを開く際には最小日付を設定します。

private void reset_Click(object sender, EventArgs e)
{
    customDatePicker.Text = "";
}

image.png

まとめ

本記事では、カスタム日付ピッカーの実装方法について解説しました。TextBox をベースに MonthCalendar をポップアップ表示し、背景色の変更やカレンダーアイコンの追加、リセット機能を実装しました。

このカスタム日付ピッカーを活用することで、デザインの自由度を高めつつ、ユーザーにとって使いやすいUIを提供できます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?