【テクニカル・上級編】NumericUpDownとTextBoxのシームレスな切り替え:フォーカス喪失時に自動でカンマ編集を行うカスタムコントロールの自社開発 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

業務UIの神髄:NumericUpDownの呪縛を解き、TextBoxを「数値編集の要」へ昇華させる

長年、VB.NETによる基幹業務システムの現場に身を置いていると、「NumericUpDown」というコントロールがいかに実務の足枷であるか、痛感させられる。スピンボタンの誤操作、独自のフォーマット制約、そして何より「UIとしての融通の利かなさ」。

真のプロフェッショナルは、標準コントロールの仕様に屈しない。今回は、`TextBox`を継承し、フォーカス状態に応じて「入力用(生数値)」と「表示用(カンマ・通貨編集)」をシームレスに切り替える、高信頼性カスタムコントロールの実装法を伝授する。

—

1. なぜ「継承」であり「UserControl」ではないのか

まず設計思想の話をする。`UserControl`に`TextBox`を配置する構成は、一見手軽だが、プロパティの多重露呈やフォーカス制御のオーバーヘッドを生む。我々が目指すのは、「既存のTextBoxと完全な互換性を持ちつつ、挙動だけを極限までチューニングした部品」だ。

したがって、`Inherits TextBox`は絶対条件である。これにより、`Control`クラスのライフサイクルを直接制御し、メモリ消費を最小化しつつ、Windows APIの介入も容易にする。

2. 実装:`FormattedNumericTextBox`のコア

この実装の肝は、`GotFocus`と`LostFocus`(または`Enter`/`Leave`)のイベントをフックし、`Text`プロパティの内容を「生データ」と「整形データ」で書き換えるタイミングの制御にある。

Imports System.ComponentModel
Imports System.Globalization

”’

”’ フォーカス喪失時に自動的にカンマ編集・通貨表示を行う高機能TextBox
”’

Public Class FormattedNumericTextBox
Inherits TextBox

‘ 通貨記号やフォーマットを保持するプライベート変数
Private _rawText As String = “”


Public Property CurrencySymbol As String = “¥”

‘ 入力中は数値のみを許可するよう制御
Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs)
‘ 数値、バックスペース、マイナス記号以外を弾く
If Not (Char.IsDigit(e.KeyChar) OrElse e.KeyChar = ControlChars.Back OrElse e.KeyChar = “-“) Then
e.Handled = True
End If
MyBase.OnKeyPress(e)
End Sub

‘ フォーカス取得時:数値のみに戻す
Protected Overrides Sub OnEnter(e As EventArgs)
MyBase.Text = _rawText
MyBase.OnEnter(e)
End Sub

‘ フォーカス喪失時:カンマと通貨記号を付与
Protected Overrides Sub OnLeave(e As EventArgs)
_rawText = MyBase.Text

Dim val As Decimal
If Decimal.TryParse(_rawText, val) Then
‘ 3桁区切り+通貨記号
MyBase.Text = String.Format(“{0}{1:N0}”, CurrencySymbol, val)
End If

MyBase.OnLeave(e)
End Sub

‘ メモリ最適化:不要なリソースは即座に解放
Protected Overrides Sub Dispose(disposing As Boolean)
If disposing Then
_rawText = Nothing
End If
MyBase.Dispose(disposing)
End Sub
End Class

3. シニアエンジニアが意識すべき「極限の知見」

① Windows APIによる描画の最適化

もし、大量のデータをグリッド状に配置した画面でこのコントロールを多用する場合、`WM_PAINT`イベントがボトルネックになる可能性がある。その際は、`SetStyle`メソッドで`UserPaint`と`DoubleBuffer`を有効にすることを忘れてはならない。

Public Sub New()
‘ ダブルバッファリングでちらつきを抑制
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint, True)
End Sub

② バインディングとビジネスロジックの分離

この実装の唯一の弱点は、データバインディング時に「整形済み文字列」がDTOに送られてしまうことだ。これを防ぐには、`DataBindings.Add`の際、`Binding.Parse`イベントと`Binding.Format`イベントをオーバーライドする必要がある。これが、業務システムの堅牢性を担保する「設計の境界線」である。

③ レガシー環境でのメモリ管理

VB.NETのガベージコレクタは優秀だが、Windows Formsのコンポーネントはしばしば`Handle`を解放し損ねる。`Dispose`メソッドをオーバーライドし、明示的な変数クリアと`GC.SuppressFinalize(Me)`の呼び出しを行うことで、長時間稼働する業務アプリの「メモリリークによるスローダウン」を確実に防ぐ。

4. 最後に:職人の矜持

UI部品は、使う側が「何も考えずに配置すれば動く」のが理想だ。しかし、その裏側にあるのは、フォーカス移動のたびにメモリを汚さない計算と、Windowsの描画サイクルを熟知した計算である。

「たかがテキストボックスのカンマ編集」と侮るなかれ。この細部に宿る品質こそが、エンドユーザーが毎日触れる業務システムの「使い心地」という名の信頼を形作る。

君たちのコードが、明日も現場で安定して稼働することを願っている。

タイトルとURLをコピーしました