現場で生き残る!VB.NETで構築する「堅牢な期間選択UI」の極意
こんにちは。現場の最前線でコードを書き続けているエンジニアです。
皆さんは、業務アプリで「開始日と終了日を選ぶカレンダー」を作ったことはありますか?ただ2つの日付ピッカーを並べるだけなら誰でもできます。しかし、「終了日が開始日より前になってしまう」「休日を選択させないようにする」といった制御を、ユーザーをイライラさせずに実装するのは、実はプロの腕の見せ所なのです。
今日は、VB.NETのWindows Formsにおける「MonthCalendar」と「DateTimePicker」を操り、堅牢で美しい日付制御を実装するノウハウを伝授します。
—
1. なぜ「連携」が難しいのか?―オブジェクトのライフサイクルを理解する
多くの初心者が陥る罠は、それぞれのコントロールをバラバラに制御しようとすることです。
Windows Formsにおいて、UIは常に「イベント」の連鎖で生きています。ユーザーが日付を変えた瞬間、背後で `ValueChanged` イベントが走り、即座に整合性チェック(バリデーション)が走る。このサイクルを意識する必要があります。
連携の基本戦略
1. 単一ソースの原則: 日付データは、UI(コントロール)ではなく、背後の変数やクラスが正とみなす。
2. イベントの連鎖を断つ: プログラムから日付を変える際、イベントが二重に発火して無限ループに陥らないようにする。
—
2. 期間選択型カレンダーの実装コード
今回は、「開始日」と「終了日」を選択し、終了日が開始日より前にならないように制御するシンプルな例を見ていきましょう。
Public Class DateManagerForm
‘ フォームロード時に初期設定
Private Sub DateManagerForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘ 終了日の最小値を今日に設定
dtpEndDate.MinDate = DateTime.Today
dtpStartDate.Value = DateTime.Today
End Sub
‘ 開始日が変更されたら、終了日のMinDateを自動更新する
Private Sub dtpStartDate_ValueChanged(sender As Object, e As EventArgs) Handles dtpStartDate.ValueChanged
‘ 終了日の最小値を開始日に同期させる(これで物理的に開始日より前には選べない)
dtpEndDate.MinDate = dtpStartDate.Value
‘ 終了日が開始日より前になってしまった場合のリカバリー
If dtpEndDate.Value < dtpStartDate.Value Then
dtpEndDate.Value = dtpStartDate.Value
End If
End Sub
' MonthCalendarで日付範囲を選択した時の処理
Private Sub monthCalendar1_DateSelected(sender As Object, e As DateRangeEventArgs) Handles MonthCalendar1.DateSelected
' 選択範囲を開始日と終了日に反映
dtpStartDate.Value = e.Start
dtpEndDate.Value = e.End
End Sub
End Class
---
3. 陥りやすいエラー:無限ループの恐怖
上記のコードで最も注意すべきは、`dtpEndDate.Value = …` を実行した瞬間に、再び `ValueChanged` イベントが発生してしまうことです。
もしあなたが、「日付が変わったらログを吐く」といった処理を書いていた場合、それが無限に繰り返され、アプリがフリーズします。これを避けるには、「フラグ管理」が有効です。
Private isUpdating As Boolean = False
Private Sub dtpEndDate_ValueChanged(sender As Object, e As EventArgs) Handles dtpEndDate.ValueChanged
If isUpdating Then Return ‘ 更新中ならイベントを無視する
isUpdating = True
Try
‘ ここにバリデーション処理を書く
Finally
isUpdating = False ‘ 必ず最後に解除する
End Try
End Sub
この「フラグでイベントをガードする」テクニックは、業務アプリ開発では必須の作法です。
—
4. プロのこだわり:休業日のハイライト表示
MonthCalendarで特定の日付を太字にするには `BoldedDates` プロパティを使います。配列として渡すのがポイントです。
‘ 休業日リストを作成してカレンダーに反映する
Dim holidays As New List(Of DateTime)
holidays.Add(New DateTime(2023, 12, 31))
holidays.Add(New DateTime(2024, 1, 1))
‘ 配列に変換してセット
MonthCalendar1.BoldedDates = holidays.ToArray()
これを応用すれば、データベースから「稼働日カレンダー」を読み込み、毎週土日を自動でハイライトさせることも可能です。
—
最後に:先輩からのアドバイス
VB.NETは「古い言語」だと言う人もいますが、それは表面しか見ていない人の言葉です。Windows Formsの深いイベントモデルを理解し、ユーザーが「どう操作するか」を想像してコードを書く力は、どんなモダンなフレームワークに行っても通用する本物のエンジニアリング能力です。
まずはこのコードを写経して、`MinDate` を操作したときにUIがどう動くか、ぜひ体感してみてください。ここをクリアすれば、あなたはもうマクロの記録から脱却した、立派なVB.NETエンジニアです。
何か詰まったら、いつでも戻ってきてくださいね。応援しています!
