Gluing It All Together
At this point, each of the program's interesting forms has SessionState property procedures. The program still needs to use them to save and restore the whole application's session state.
ApplicationSessionState Property get
The program's main MDI form has ApplicationSessionState property procedures that save and restore all of the forms' combined session states. The property get procedure, shown in Listing 4, creates a new XmlDocument, and gives it a node named SessionState. It then calls the MakeFormSessionStateNode subroutine to add the main form's session state to that node.
MakeFormSessionStateNode, shown at the end of Listing 4, makes a temporary node that contains the text of the form's session state. It pulls the temporary node's child containing the form's session state out and moves it into the XML document's SessionState node. It then deletes the temporary node.
This little sleight-of-hand makes creating the form's node easier. It would be more direct to create the form's node and then set its OuterXml property to the form's SessionState value, but OuterXml is a read-only property. The MakeXmlNode subroutine can set the InnerXml property, but that adds an extra layer to the hierarchy. That's why MakeFormSessionStateNode moves the form's session state node up one level in the document hierarchy.
After adding the main MDI form's SessionState to the XML document, the program loops through the forms listed in the m_Forms collection, adding their information to the document.
Listing 4. The ApplicationSessionState Property get Procedure Returns a Representation of the Entire Application's Session State
' Get/set session state for the entire application. Private Property ApplicationSessionState() As String Get Dim doc As New XmlDocument() Dim root_node As XmlNode Dim frm As Form ' Make the XML root node. root_node = MakeXmlNode(doc, "SessionState") ' Make a session state node for ' the main form. MakeFormSessionStateNode(root_node, Me) ' Make session state nodes for ' the other forms. For Each frm In m_Forms MakeFormSessionStateNode(root_node, frm) Next frm ' Return the combined session state. Return doc.InnerXml End Get ... End Property ' Make a node representing the session state ' for the form. Private Sub MakeFormSessionStateNode(ByVal parent As XmlNode, ByVal frm As Object) Dim temp_node As XmlNode ' Save the form's information. This makes ' a node named Temp with a single child ' node holding the form's information. temp_node = MakeXmlNode(parent, "Temp", frm.SessionState) ' Move the form's information node into ' the parent node. parent.AppendChild(temp_node.ChildNodes(0)) ' Remove the temporary node. parent.RemoveChild(temp_node) End Sub
The following code shows the result. Notice that the SessionState node contains the MainForm and CustomerListForm nodes. If more forms were visible when the program saved its state, the document might contain other CustomerListForm and EmployeeListForm nodes.
<SessionState> <MainForm> <X>291</X> <Y>16</Y> <Width>714</Width> <Height>508</Height> </MainForm> <CustomerListForm> <ActiveForm /> <X>0</X> <Y>0</Y> <Width>701</Width> <Height>227</Height> <Field1>Company Name</Field1> <Field2>City</Field2> <Operator1>LIKE</Operator1> <Operator2>=</Operator2> <Value1>%Inc%</Value1> <Value2>Boulder</Value2> </CustomerListForm> </SessionState>"
To be well-formed, an XML document must have a single data root node. In this case, that is the SessionState node. This property procedure and subroutine MakeFormSessionStateNode go to some lengths to ensure that the combined session state has a single root node.
ApplicationSessionState Property set
The ApplicationSessionState property set procedure, shown in Listing 5, takes a string containing session information and uses it to reset the application. It uses the information it has to create an XmlDocument. It then loops through the root data node's children. In the previous XML listing, those are the nodes named MainForm and CustomerListForm.
The procedure examines each of the child nodes' names to see what kind of form it represents. If the node represents the main form, the program sets the main form's SessionState property using the node's value. That makes the main form reset its size and position.
If the node represents some other kind of form, the procedure creates a new form of the appropriate type. Then it sets the new form's SessionState property using the node's value to make the form reload its session state. The procedure sets the form's MDI parent to the main MDI form and displays the new form.
If the form's session state information contains a child named ActiveForm, that form had the focus when the program saved its session state. The procedure saves a reference to the form in the variable active_form. After it has re-created all the forms, the procedure gives that form the focus.
Listing 5. The ApplicationSessionState Property set Procedure Resets the Application's Session State
' Get/set session state for the entire application. Private Property ApplicationSessionState() As String ... Set(ByVal Value As String) Dim doc As New XmlDocument() Dim form_node As XmlNode Dim employee_list_form As EmployeeListForm Dim customer_list_form As CustomerListForm Dim active_form As Form ' Load the XML document from the session ' state information. doc.InnerXml = Value ' Loop through the form information nodes. For Each form_node In doc.DocumentElement.ChildNodes ' Load the appropriate form. Select Case form_node.Name Case "MainForm" Me.SessionState = form_node.OuterXml Case "CustomerListForm" customer_list_form = New CustomerListForm() customer_list_form.StartPosition = FormStartPosition.Manual customer_list_form.SessionState = form_node.OuterXml customer_list_form.MdiParent = Me customer_list_form.Show() ' See if this should be the active form. If Not (form_node.Item("ActiveForm") Is Nothing) Then active_form = customer_list_form End If Case "EmployeeListForm" employee_list_form = New EmployeeListForm() employee_list_form.StartPosition = FormStartPosition.Manual employee_list_form.SessionState = form_node.OuterXml employee_list_form.MdiParent = Me employee_list_form.Show() ' See if this should be the active form. If Not (form_node.Item("ActiveForm") Is Nothing) Then active_form = employee_list_form End If End Select Next form_node ' Set the active form. If Not (active_form Is Nothing) Then active_form.Focus() End If End Set End Property
That's about all there is to it. When you select the Save Session command, the program saves the ApplicationSessionState value in the registry. When you restart the program or invoke the Restore Saved Session command, the program sets ApplicationSessionState to the value retrieved from the registry.
Download the program Restore here: