We will cover three topics in one
- Using a single settings variable to save ever forms window state
- Base class inheritance in winforms
- Data contracts and JSON
In a nutshell, we will serialise and deserialise into a strongly typed custom settings class to and from JSON to store out our windows forms window states, in a settings variable in the project, using a custom settings class that is present in a baseClass that every form within your project will inherit from
What are data contracts
A data contract is essentially a simple way of serialising a class into a string for storage and/or transport
In simple terms, when you mark a class as a data contract you are telling .NET that this class will have properties that can be stored as a string (in our case serialised to JSON).
this is how to mark a class as a data contract
|
<Runtime.Serialization.DataContract()> Friend Class ScreenSizePosition |
And members that you would like to store in your JSON should be marked as data members like so
|
<Runtime.Serialization.DataContract()> Friend Class FormSizeLocation <Runtime.Serialization.DataMember> Property name As String |
How do data contracts work with JSON?
A long time ago I wrote a generic serialiser/deserialiser to convert datacontract classes to and from JSON, this is the code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
Public Class JSONHelper Public Shared Function Serialize(Of T)(ByVal obj As T) As String Dim serializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.[GetType]()) Dim ms As New IO.MemoryStream() serializer.WriteObject(ms, obj) Dim retVal As String = System.Text.Encoding.[Default].GetString(ms.ToArray()) ms.Dispose() Return retVal End Function Public Shared Function Deserialize(Of T)(ByVal json As String) As T Dim obj As T = Activator.CreateInstance(Of T)() Dim ms As New IO.MemoryStream(System.Text.Encoding.Unicode.GetBytes(json)) Dim serializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.[GetType]()) obj = DirectCast(serializer.ReadObject(ms), T) ms.Close() ms.Dispose() Return obj End Function End Class |
we are going to reference these function later in this article
How do we use inheritance in winforms
Windows forms classes that you are exposed to are essentially partial classes. If you have a project open that contains a Windows.Forms.Form, then unhide all documents and take a look at the difference between the code behind the form that you see and the designer generated code. The file names will have this structure
- frmName.vb
- frmName.designer.vb
|
Partial Class frmName Inherits System.Windows.Forms.Form |
Partial classes are a really nice way to extend the reach of a single class, but separate the code file
So, create a baseclass ready to be inherited by all of your windows forms
- frmName.vb
- frmName.designer.vb
|
Partial Class frmName Inherits BaseForm |
- BaseForm.vb
|
Public Class BaseForm Inherits System.Windows.Forms.Form |
create the project settings property
next we create our custom project settings property “FormSizesAndLocations”

The custom settings class
we need our settings class to be able to do the following
- read the settings from the config
- save a forms window state to the config
- name, width, height, x position, y position, maximised, minimised
here is our custom settings class for saving window state and reading window state, note the data contract attribute and the data member attributes to those properties we want to persist
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
<Serializable, Runtime.Serialization.DataContract()> Friend Class ScreenSizePosition Const SettingsVarName As String = "FormSizesAndLocations" <Runtime.Serialization.DataMember> Public Property SizeLocationOfForms As New List(Of FormSizeLocation) <Serializable, Runtime.Serialization.DataContract()> Friend Class FormSizeLocation <Runtime.Serialization.DataMember> Property name As String <Runtime.Serialization.DataMember> Property width As Integer <Runtime.Serialization.DataMember> Property height As Integer <Runtime.Serialization.DataMember> Property X As Integer <Runtime.Serialization.DataMember> Property Y As Integer <Runtime.Serialization.DataMember> Property maximised As Boolean <Runtime.Serialization.DataMember> Property minimised As Boolean End Class Sub New() End Sub Sub New(bool As Boolean) Dim myforms As ScreenSizePosition = Nothing Dim str As String = Nothing If bool Then str = My.Settings.FormSizesAndLocations Try myforms = JSONHelper.Deserialize(Of ScreenSizePosition)(str) Me.SizeLocationOfForms = myforms.SizeLocationOfForms Catch ex As Exception 'cannot read the state, dont really care ' End Try End Sub Function GetForm(name As String) As FormSizeLocation Dim rtn As FormSizeLocation = Nothing rtn = Me.SizeLocationOfForms.Find(Function(e) e.name = name) Return rtn End Function Sub AddUpdateForm(frm As FormSizeLocation) Dim removeItem As FormSizeLocation = Me.SizeLocationOfForms.Find(Function(e) e.name = frm.name) If removeItem IsNot Nothing Then Me.SizeLocationOfForms.Remove(removeItem) Me.SizeLocationOfForms.Add(frm) Save() End Sub Sub Save() My.Settings.GetType.GetProperty(SettingsVarName).SetValue(My.Settings, JSONHelper.Serialize(Of ScreenSizePosition)(Me)) 'My.Settings.FormSizesAndLocations = SFCL.CFC.JSONHelper.Serialize(Of ScreenSizePosition)(Me) ' 'My.Settings.Save() ' End Sub End Class |
The BasePage class that will do all the work
Now lets create a base page class, in this class we will put the logic to handle the position save and load of any form that then inherits this class
Rather than describe the code, you should really be able to understand it, so lets dive into the forms base class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
Imports System.ComponentModel Imports System.Windows.Forms Public Class BaseForm Inherits System.Windows.Forms.Form Property HasSavedWindowsState As Boolean = False Private Sub BaseForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing SaveWindowPosition() End Sub Private Sub BaseForm_Load(sender As Object, e As EventArgs) Handles Me.Load loadWindowPosition() End Sub Sub loadWindowPosition() Dim curSizePosition As New ScreenSizePosition(True) Dim thisForm As ScreenSizePosition.FormSizeLocation = curSizePosition.GetForm(Me.Name) If thisForm IsNot Nothing Then With thisForm HasSavedWindowsState = True Me.Location = New Drawing.Point(thisForm.X, thisForm.Y) Me.Size = New Drawing.Size(thisForm.width, thisForm.height) If .maximised Then Me.WindowState = FormWindowState.Maximized ElseIf .minimised Then Me.WindowState = FormWindowState.Minimized End If End With End If End Sub Sub SaveWindowPosition() Dim curSizePosition As New ScreenSizePosition(True) Dim thisForm As ScreenSizePosition.FormSizeLocation = curSizePosition.GetForm(Me.Name) If thisForm Is Nothing Then thisForm = New ScreenSizePosition.FormSizeLocation With thisForm .name = Me.Name .X = Me.Location.X .Y = Me.Location.Y .height = Me.Size.Height .width = Me.Size.Width If WindowState = FormWindowState.Maximized Then .maximised = True .minimised = False ElseIf WindowState = FormWindowState.Normal Then .maximised = False .minimised = False Else .maximised = False .minimised = True End If End With curSizePosition.AddUpdateForm(thisForm) End Sub End Class |
And there you have it