こんにちは!開発現場を渡り歩いてきた、あなたの専属シニアアーキテクトです。
今回は、Windows Formsアプリケーション開発において誰もが一度は直面する、そして多くのプログラマーが泥沼にはまりがちな「アプリケーション設定(My.Settings)の極限活用術」を伝授します。
「ユーザーが窓のサイズを変更したり、グリッドの列幅をカスタマイズしたりした配置を、次にアプリを開いたときにも完璧に復元したい!」
そんな現場からの熱い要望に応えるために、単なる文字列や数値の保存を超え、「ユーザー定義クラスのシリアライズ」と「ウィンドウ状態の完全復元」をVB.NETで実現する方法を解説します。
ここをクリアすれば、あなたのWindows Formsアプリは「おもちゃ」から「プロフェッショナルな業務システム」へと生まれ変わります。一緒にマスターしていきましょう!
—
1. なぜ「My.Settings」だけでは複雑な画面状態を保存できないのか?
Visual Basicには、`My.Settings`という非常に強力で手軽な設定保存機能が用意されています。
例えば、「テキストボックスに入力された文字」や「チェックボックスの状態」程度であれば、プロジェクトのプロパティから設定画面を開き、数値をポチポチと登録するだけで自動保存してくれます。
しかし、ここで大きな壁にぶつかります。
DataGridViewの「どの列がどの順番で並んでいて、幅がいくつで、どの列が非表示になっているか」といった複雑な構造体やオブジェクトのリストは、標準の`My.Settings`の型(StringやIntegerなど)には直接格納できません。
ここで多くの初心者が「全部のプロパティをバラバラの変数にして設定に詰め込む」というスパゲッティコードの迷宮に入り込んでしまいます。
それをスマートに解決するのが、「XMLシリアライズ」という技術です。
—
2. 解決の鍵:ユーザー定義クラスのシリアライズとは?
シリアライズ(直列化)とは、メモリ上にある複雑なオブジェクト(データ構造)を、ファイルや文字列(今回はXML)に「一本の平らなデータ」として書き出す技術です。そして、それを再び読み込んで元のオブジェクトに戻すことをデシリアライズと呼びます。
今回は、ウィンドウの位置・サイズ、そしてDataGridViewのレイアウト情報をまとめた「設定保持用の専用クラス」を作りこみます。
実装コード:ウィンドウとグリッド状態を保持するクラス
まずは、保存したいデータをカプセル化(まとめる)したクラスを定義します。VB.NETの属性(Attribute)を使って、XMLとして書き出しやすい形にします。
Public Class AppLayoutSettings
‘ ウィンドウの位置とサイズ
uxProperty WindowLeft As Integer = 100
Public Property WindowTop As Integer = 100
Public Property WindowWidth As Integer = 800
Public Property WindowHeight As Integer = 600
Public Property WindowState As Integer = 0 ‘ 0:通常, 1:最小化, 2:最大化
‘ DataGridViewの列幅や順序を保持するリスト(DTOクラス)
Public Property ColumnStates As List(Of ColumnLayoutInfo) = New List(Of ColumnLayoutInfo)()
End Class
Public Class ColumnLayoutInfo
Public Property ColumnName As String = String.Empty
Public Property Width As Integer = 100
Public Property DisplayIndex As Integer = 0
Public Property Visible As Boolean = True
End Class
💡 先輩からのワンポイントアドバイス:
`_`(アンダースコア)を使ったインデントや `
—
3. 実践!ウィンドウ状態とグリッドの完全復元フロー
では、実際のWindows Forms(Form1)にこの仕組みを組み込んでみましょう。
アプリケーションの終了時(`FormClosing`)に現在の状態をシリアライズして`My.Settings`(String型)に保存し、起動時(`Load`)にそれを復元します。
フォームの全コード例(コピペで動く実用コード)
Imports System.IO
Imports System.Xml.Serialization
Public Class Form1
‘ 設定を保持する実体
Private currentSettings As AppLayoutSettings
Private Sub Form1_Load(sender As Object, e EventArgs) Handles MyBase.Load
‘ 1. 保存された設定をロードする(なければ新規作成)
LoadApplicationSettings()
‘ 2. ウィンドウの状態を復元
Me.StartPosition = FormStartPosition.Manual
Me.Left = currentSettings.WindowLeft
Me.Top = currentSettings.WindowTop
Me.Width = currentSettings.WindowWidth
Me.Height = currentSettings.WindowHeight
Me.WindowState = CType(currentSettings.WindowState, FormWindowState)
‘ 3. ダミーデータのバインドとグリッドレイアウトの復元
InitializeDataGridView()
ApplyGridLayout()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
‘ 1. 現在のウィンドウ状態をクラスに格納
currentSettings.WindowLeft = Me.Left
currentSettings.WindowTop = Me.Top
currentSettings.WindowWidth = Me.Width
currentSettings.WindowHeight = Me.Height
currentSettings.WindowState = CType(Me.WindowState, Integer)
‘ 2. グリッドの現在の状態をクラスに格納
CaptureGridLayout()
‘ 3. XML文字列にシリアライズして My.Settings に保存
SaveApplicationSettings()
End Sub
‘ — 以下、シリアライズとグリッド操作の核心ロジック —
Private Sub LoadApplicationSettings()
Try
‘ My.Settings に保存されているXML文字列を取得
Dim xmlData As String = My.Settings.SavedLayoutXml
If String.IsNullOrEmpty(xmlData) Then
currentSettings = New AppLayoutSettings()
Exit Sub
End If
‘ XML文字列をオブジェクトに復元(デシリアライズ)
Dim serializer As New XmlSerializer(GetType(AppLayoutSettings))
Using reader As New StringReader(xmlData)
currentSettings = CType(serializer.Deserialize(reader), AppLayoutSettings)
End Using
Catch ex As Exception
‘ 予期せぬ設定ファイルの破損に備え、エラー時はデフォルトでフォールバック
MessageBox.Show(“設定の読み込みに失敗しました。初期設定で起動します。”, “警告”, MessageBoxButtons.OK, MessageBoxIcon.Warning)
currentSettings = New AppLayoutSettings()
End Try
End Sub
Private Sub SaveApplicationSettings()
Try
Dim serializer As New XmlSerializer(GetType(AppLayoutSettings))
Using writer As New StringWriter()
serializer.Serialize(writer, currentSettings)
‘ My.Settings の String型プロペティにXMLをそのまま保存
My.Settings.SavedLayoutXml = writer.ToString()
My.Settings.Save() ‘ ディスクへの書き込みを確定
End Using
Catch ex As Exception
MessageBox.Show(“設定の保存に失敗しました: ” & ex.Message, “エラー”, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Private Sub InitializeDataGridView()
‘ テスト用の列とデータをDataGridViewに追加
DataGridView1.Columns.Clear()
DataGridView1.Columns.Add(“ColID”, “ID”)
DataGridView1.Columns.Add(“ColName”, “顧客名”)
DataGridView1.Columns.Add(“ColDate”, “登録日”)
DataGridView1.Rows.Add(“1”, “山田 太郎”, “2023-01-01”)
DataGridView1.Rows.Add(“2”, “鈴木 花子”, “2023-05-15”)
End Sub
Private Sub CaptureGridLayout()
currentSettings.ColumnStates.Clear()
For Each col As DataGridViewColumn In DataGridView1.Columns
Dim info As New ColumnLayoutInfoWith
info.ColumnName = col.Name
info.Width = col.Width
info.DisplayIndex = col.DisplayIndex
info.Visible = col.Visible
currentSettings.ColumnStates.Add(info)
Next
End Sub
Private Sub ApplyGridLayout()
If currentSettings.ColumnStates Is Nothing OrElse currentSettings.ColumnStates.Count = 0 Then Exit Sub
‘ 保存された順序・幅を各列に適用
For Each info In currentSettings.ColumnStates
Dim col = DataGridView1.Columns(info.ColumnName)
If col Is not Nothing Then
col.Width = info.Width
col.DisplayIndex = info.DisplayIndex
col.Visible = info.Visible
End If
Next
End Sub
End Class
—
4. 現場で陥りやすい罠とエラー回避のポイント
ここで、実務で絶対にハマるポイントをいくつか先回りして解説しておきます。
1. `My.Settings` にプロパティを追加し忘れる
今回のコードを動かすには、プロジェクトのプロパティ > [設定] タブを開き、以下の設定を追加する必要があります。
- 名前: `SavedLayoutXml`
- 種類: `String`
- スコープ: `User`
- 値: (空欄でOK)
これを忘れるとコンパイルエラーや実行時例外が発生します。必ず最初に行いましょう。
2. マルチモニター環境でのウィンドウ位置迷子バグ
ユーザーが会社でデュアルモニターの「サブ画面」にアプリを配置したまま退勤し、翌日自宅の「シングルモニター(ノートPC単体)」でアプリを起動したとき、ウィンドウが画面の外(座標の彼方)に配置されて二度と開けなくなるという恐ろしい事故がよく起きます。
これを防ぐためには、`Load` イベントの直後に「画面の有効領域(`Screen.GetWorkingArea`)内にウィンドウが含まれているか」をチェックする防護壁(バリデーション)を入れるのが、一流のエンジニアの作法です。
‘ ※応用:画面外にはみ出ていないかチェックするロジックの例
Dim screenBounds As Rectangle = Screen.GetWorkingArea(Me)
If Not screenBounds.IntersectsWith(New Rectangle(currentSettings.WindowLeft, currentSettings.WindowTop, currentSettings.WindowWidth, currentSettings.WindowHeight)) Then
‘ はみ出していたら安全なデフォルト位置に戻す
Me.StartPosition = FormStartPosition.WindowsDefaultLocation
End If
—
5. まとめ
今回は、Visual Basicを使ったWindows Formsアプリケーションにおける「ユーザー定義クラスのシリアライズ」と「ウィンドウ・グリッド状態の完全復元」について解説しました。
- 複雑なデータ構造は `XmlSerializer` を使ってXML文字列に変換する。
- 変換した文字列を `My.Settings`(String型)に丸ごと保存する。
- 起動時に逆変換(デシリアライズ)して、フォームやコントロールに適用する。
このパターンを一度自分のものにしてしまえば、どんなに複雑なユーザー設定を持つ業務アプリケーションであっても、驚くほどスマートに実装できるようになります。
「ここをクリアすれば、Visual Basicの基本はバッチリですよ!」
ぜひ、あなたの開発するアプリケーションにこの仕組みを組み込んで、使い心地の素晴らしいシステムを作り上げてください。応援しています!
