Results 1 to 17 of 17

Thread: [RESOLVED] Serialization of a Windows Form State - Help to refine the code

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Resolved [RESOLVED] Serialization of a Windows Form State - Help to refine the code

    Hello

    At this time, in a code to save information, there is no software that you are creating.

    First: the application has a series of windows, where the user types and strings. So in the end, I do not need a database to save everything, because it's not much to save. I've chosen to use the serialization method, saving everything to an .xml file.

    But like every beginner, I have some doubts:
    1) In my software, the various windows, which perform codepentes activities, the result of one and used in the following. And it is not a process with some calculations, and it turns out that I intend to generate a final report.
    Returning to the serialization, I have how to save data from all forms to a single .xml file? Or do I need to generate a file for each form?

    2) Second question: When the user clicks save, how can I provide the option for him to choose where he wants to save the project .xml file? Even when he returns to complete the work he has saved, can I open a window for him to get the .xml file he saved?

    Currently I'm following the following serialization structure:

    I created a class called "Serialize.vb" (Serialise, in portuguese)

    Code:
    Imports System
    Imports System.IO
    Imports System.Windows.Forms
    Imports System.Reflection
    Imports System.Xml
    Imports System.Diagnostics
    
    Public Class Serializar
        Public Sub New()
    
        End Sub
    
        Public Shared Sub Serialise(ByVal c As Control, ByVal XmlFileName As String)
            Dim xmlSerialisedForm As XmlTextWriter = New XmlTextWriter(XmlFileName, System.Text.Encoding.[Default])
            xmlSerialisedForm.Formatting = Formatting.Indented
            xmlSerialisedForm.WriteStartDocument()
            xmlSerialisedForm.WriteStartElement("ChildForm")
            AddChildControls(xmlSerialisedForm, c)
            xmlSerialisedForm.WriteEndElement()
            xmlSerialisedForm.WriteEndDocument()
            xmlSerialisedForm.Flush()
            xmlSerialisedForm.Close()
        End Sub
    
    
        Private Shared Sub AddChildControls(ByVal xmlSerialisedForm As XmlTextWriter, ByVal c As Control)
            For Each childCtrl As Control In c.Controls
    
                If Not (TypeOf childCtrl Is Label) Then
                    xmlSerialisedForm.WriteStartElement("Control")
                    xmlSerialisedForm.WriteAttributeString("Type", childCtrl.[GetType]().ToString())
                    xmlSerialisedForm.WriteAttributeString("Name", childCtrl.Name)
    
                    If TypeOf childCtrl Is TextBox Then
                        xmlSerialisedForm.WriteElementString("Text", (CType(childCtrl, TextBox)).Text)
                    ElseIf TypeOf childCtrl Is Label Then
                        xmlSerialisedForm.WriteElementString("Text", (CType(childCtrl, Label)).Text)
                    ElseIf TypeOf childCtrl Is ComboBox Then
                        xmlSerialisedForm.WriteElementString("Text", (CType(childCtrl, ComboBox)).Text)
                        xmlSerialisedForm.WriteElementString("SelectedIndex", (CType(childCtrl, ComboBox)).SelectedIndex.ToString())
                    ElseIf TypeOf childCtrl Is ListBox Then
                        Dim lst As ListBox = CType(childCtrl, ListBox)
    
                        If lst.SelectedIndex = -1 Then
                            xmlSerialisedForm.WriteElementString("SelectedIndex", "-1")
                        Else
    
                            For i As Integer = 0 To lst.SelectedIndices.Count - 1
                                xmlSerialisedForm.WriteElementString("SelectedIndex", (lst.SelectedIndices(i).ToString()))
                            Next
                        End If
                    ElseIf TypeOf childCtrl Is CheckBox Then
                        xmlSerialisedForm.WriteElementString("Checked", (CType(childCtrl, CheckBox)).Checked.ToString())
                    ElseIf TypeOf childCtrl Is RadioButton Then
                        xmlSerialisedForm.WriteElementString("Checked", (CType(childCtrl, RadioButton)).Checked.ToString())
                    ElseIf TypeOf childCtrl Is Button Then
                        xmlSerialisedForm.WriteElementString("Enabled", (CType(childCtrl, Button)).Enabled.ToString())
                    End If
    
                    Dim visible As Boolean = CBool(GetType(Control).GetMethod("GetState", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(childCtrl, New Object() {2}))
                    xmlSerialisedForm.WriteElementString("Visible", visible.ToString())
    
                    If childCtrl.HasChildren Then
    
                        If TypeOf childCtrl Is SplitContainer Then
                            AddChildControls(xmlSerialisedForm, (CType(childCtrl, SplitContainer)).Panel1)
                            AddChildControls(xmlSerialisedForm, (CType(childCtrl, SplitContainer)).Panel2)
                        Else
                            AddChildControls(xmlSerialisedForm, childCtrl)
                        End If
                    End If
    
                    xmlSerialisedForm.WriteEndElement()
                End If
            Next
        End Sub
    
        Public Shared Sub Deserialise(ByVal c As Control, ByVal XmlFileName As String)
            If File.Exists(XmlFileName) Then
                Dim xmlSerialisedForm As XmlDocument = New XmlDocument()
                xmlSerialisedForm.Load(XmlFileName)
                Dim topLevel As XmlNode = xmlSerialisedForm.ChildNodes(1)
    
                For Each n As XmlNode In topLevel.ChildNodes
                    SetControlProperties(CType(c, Control), n)
                Next
            End If
        End Sub
    
        Private Shared Sub SetControlProperties(ByVal currentCtrl As Control, ByVal n As XmlNode)
            Dim controlName As String = n.Attributes("Name").Value
            Dim controlType As String = n.Attributes("Type").Value
            Dim ctrl As Control() = currentCtrl.Controls.Find(controlName, True)
    
            If ctrl.Length = 0 Then
            Else
                Dim ctrlToSet As Control = GetImmediateChildControl(ctrl, currentCtrl)
    
                If ctrlToSet IsNot Nothing Then
    
                    If ctrlToSet.[GetType]().ToString() = controlType Then
    
                        Select Case controlType
    
                            Case "System.Windows.Forms.TextBox"
                                CType(ctrlToSet, System.Windows.Forms.TextBox).Text = n("Text").InnerText
                            Case "System.Windows.Forms.Label"
                                CType(ctrlToSet, System.Windows.Forms.Label).Text = n("Text").InnerText
                            Case "System.Windows.Forms.ComboBox"
                                CType(ctrlToSet, System.Windows.Forms.ComboBox).Text = n("Text").InnerText
                                CType(ctrlToSet, System.Windows.Forms.ComboBox).SelectedIndex = Convert.ToInt32(n("SelectedIndex").InnerText)
                            Case "System.Windows.Forms.ListBox"
                                Dim lst As ListBox = CType(ctrlToSet, ListBox)
                                Dim xnlSelectedIndex As XmlNodeList = n.SelectNodes("SelectedIndex")
    
                                For i As Integer = 0 To xnlSelectedIndex.Count - 1
                                    lst.SelectedIndex = Convert.ToInt32(xnlSelectedIndex(i).InnerText)
                                Next
                            Case "System.Windows.Forms.CheckBox"
                                CType(ctrlToSet, System.Windows.Forms.CheckBox).Checked = Convert.ToBoolean(n("Checked").InnerText)
    
                        End Select
    
                        ctrlToSet.Visible = Convert.ToBoolean(n("Visible").InnerText)
    
                        If n.HasChildNodes AndAlso ctrlToSet.HasChildren Then
                            Dim xnlControls As XmlNodeList = n.SelectNodes("Control")
    
                            For Each n2 As XmlNode In xnlControls
                                SetControlProperties(ctrlToSet, n2)
                            Next
                        End If
                    Else
                    End If
                Else
                End If
            End If
        End Sub
    
        Private Shared Function GetImmediateChildControl(ByVal ctrl As Control(), ByVal currentCtrl As Control) As Control
            Dim c As Control = Nothing
    
            For i As Integer = 0 To ctrl.Length - 1
    
                If (ctrl(i).Parent.Name = currentCtrl.Name) OrElse (TypeOf currentCtrl Is SplitContainer AndAlso ctrl(i).Parent.Parent.Name = currentCtrl.Name) Then
                    c = ctrl(i)
                    Exit For
                End If
            Next
    
            Return c
        End Function
    End Class
    Then in the WindowsForm, I call the serialization when the user clicks in the button Save:
    Code:
     Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
    
            Serializar.Serialise(Me, Application.StartupPath + "\side_predimensionamento.xml")
        End Sub
    And open the file when the user clicks in the button Open
    Code:
       Private Sub btnOpen_Click(sender As Object, e As EventArgs) Handles btnOpen.Click
            Serializar.Deserialise(Me, Application.StartupPath + "\side_predimensionamento.xml")
        End Sub
    Use this article to obtain this method of serialization. I've converted from C # to VB.NET, which I'm using. https://www.codeproject.com/Articles...a-Windows-Form

    A appreciate all help.

    Thanks

  2. #2
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    First, go to Settings in Project-->Properties. Add a new String setting named 'xmlPath'

    Code:
    Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
        'declare new SaveFileDialog + set it's initial properties
        Dim sfd As New SaveFileDialog With { _
        .Title = "Choose file to save to", _
        .Filter = "XML (*.xml)|*.xml", _
        .FilterIndex = 0, _
        .InitialDirectory = Application.StartupPath}
    
        'show the dialog
        If sfd.ShowDialog = DialogResult.OK Then
            My.Settings.xmlPath = sfd.FileName
            Serializar.Serialise(Me, sfd.FileName)
        End If
    End Sub
    Code:
    Private Sub btnOpen_Click(sender As Object, e As EventArgs) Handles btnOpen.Click
        Serializar.Deserialise(Me, My.Settings.xmlPath)
    End Sub

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Hi.. Thank you so much for the answer.

    I tryed. In the saving event it is working. I was able to save wherever I wanted and with the name I choose. But when I close, and return to open the file, it gets the last one saved. Not ame to allowing me to choose the file.

    I created the string like this (see picture). It is correct?
    Name:  Capture.jpg
Views: 158
Size:  21.7 KBName:  Capture.jpg
Views: 158
Size:  21.7 KB

    Returning to my other question, I realized the text was very confusing. So I rewrited:
    1) In my software, there are many windows, each one make part of a final project. Like parts of a calculation dimensioning. Its is usual the one windows use the information resultant from the previous one.
    I want to know how to save data from all forms into a single .xml. Or, if this first operation is not possible, if I need to generate a file for each form.

  4. #4

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Hi.. Thank you so much for the answer.

    I tryed. In the saving event it is working. I was able to save wherever I wanted and with the name I choose. But when I close, and return to open the file, it gets the last one saved. Not ame to allowing me to choose the file.

    I created the string like this (see picture). Is it correct?
    Name:  Capture.jpg
Views: 158
Size:  21.7 KB

    Returning to my other question, I realized the text was very confusing. So I rewrited:
    1) In my software, there are many windows, each one make part of a final project. Like parts of a calculation dimensioning. Its is usual the one windows use the information resultant from the previous one.
    I want to know how to save data from all forms into a single .xml. Or, if this first operation is not possible, if I need to generate a file for each form.

    Thanks

  5. #5
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    Ok. See the OpenFileDialog, here...

    http://www.scproject.biz/Using%20Dialogs.php

  6. #6

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Thank you very much. I have the idea of the OpenDialog. I am just having problems with the Deserialise function now. It does not recognize the new file that I choose to deserialize in the form.

    I used this lines in the Open Button:
    Code:
    Private Sub ts_Open_Click(sender As Object, e As EventArgs) Handles ts_Open.Click
    
            Dim ofd As New OpenFileDialog With {
              .Title = "Escolha arwuivo para abrir",
             .Filter = "XML (*.xml)|*.xml",
             .FilterIndex = 0,
             .InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}
    
            'show the dialog + display the results in a msgbox unless cancelled
            If ofd.ShowDialog = DialogResult.OK Then
                MessageBox.Show(String.Format("You chose: {0}{0}{1}", Environment.NewLine,
                                If(String.Join(Environment.NewLine, ofd.FileNames), ofd.FileName)))
                My.Settings.xmlPath = String.Join(Environment.NewLine, ofd.FileNames)
                Serializar.Deserialise(Me, My.Settings.xmlPath)
            End If
    
        End Sub

    But the deserialize function only works when I try to open the last saved xml file. If you try to open any other file, with other data information, that were not saved in the last run on the system. An Exception System.Xml.XmlException error appears (see picture) in the Private Sub deserialize of the Serialize class (see full code of the class in the first post I made)

    I'm not sure how to modify this function to work with any previously saved file. I was thinking of creating a variable that would keep the location of the chosen file and would give it to the Deserialize sub. But I do not know if this is the way to go to solve it, or how to do it.

    From what I understand, I will need an xml for each form. As I have several, I wantto make the user choose the folder where to save on the first screen, and in the following the program automatically saves in the same folder with a default name. Any idea? I think that what I want to do is related to the solution of this current problem. I would like to rely on the experience of more experienced programmers to help me do this efficiently.
    Name:  Capture.jpg
Views: 161
Size:  35.5 KB


    I appreciate the help.

  7. #7
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    You need to loop through ofd.FileNames and deserialize one file at a time...

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Quote Originally Posted by .paul. View Post
    You need to loop through ofd.FileNames and deserialize one file at a time...
    I'm sorry for the inconvenience, but where do I do this? In Private Sub Deserialise?

  9. #9
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    Ofd.filenames is an array of strings which represents multiple filenames. The OpenFileDialog allows you to open multiple files, but deserializing only works with one file at a time.

    Instead of...

    Code:
    My.Settings.xmlPath = String.Join(Environment.NewLine, ofd.FileNames)
    Serializar.Deserialise(Me, My.Settings.xmlPath)
    Code:
    For each filename as string in ofd.filenames
        Serializar.Deserialise(Me, filename)
    Next

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Thanks for trying to help. But it is still not working. I'm having a really hard time trying to understand how this works. The commands that call the Deserialize function are not sending the file path to the function. This is what I understand, because the error message is Missing root element. It seems that the Deserialze function does not understand which xml file I want to open. It only opens the last xml file saved, and none else.


    I'll keep trying here.

  11. #11
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    The my.settings idea i gave you saves one file path. Ignore that for a moment. If you use an OpenFileDialog with MultiSelect set to true, the ofd.filenames returns an array of file paths. I don't know which form you intend to deserialize. That's up to you to figure out. If you get an array of filepaths and keep deserializing to the same object, all you're going to see is the last deserialization.

  12. #12

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Quote Originally Posted by veronica.sa View Post
    Thanks for trying to help. But it is still not working. I'm having a really hard time trying to understand how this works. The commands that call the Deserialize function are not sending the file path to the function. This is what I understand, because the error message is Missing root element. It seems that the Deserialze function does not understand which xml file I want to open. It only opens the last xml file saved, and none else.


    I'll keep trying here.
    I found out now, researching that could be a problem in the xml file, and apparently that was it. I'm testing, generating other projects and saving and trying to open. It's working.

    Thank you so much for your patience and for sharing your knowledge. Every time I ask for help and receive it, I am very happy with the new learning.

  13. #13
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    Glad to help...��

  14. #14

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Quote Originally Posted by .paul. View Post
    The my.settings idea i gave you saves one file path. Ignore that for a moment. If you use an OpenFileDialog with MultiSelect set to true, the ofd.filenames returns an array of file paths. I don't know which form you intend to deserialize. That's up to you to figure out. If you get an array of filepaths and keep deserializing to the same object, all you're going to see is the last deserialization.
    Thank you very much. For now I was trying to deserialize a specific form, to understand the logic of how this works. But the idea is to deserialize all the forms related to a project, when the user chooses to works with this project at the beginning of the application. Maybe I can keep the folder path where all the forms are saved, and thus deserialize them inside the Private Sub LoadForm. But first, I also need to think about how to ensure that all xml (which I think would have to be on for each window) are saved in the same folder. Maybe I have to force the user to create a folder with the project name, and inside it I would save the xml files of each form with default names.
    I am still trying to figure out the best way to do this. This saving an open proejcts is a curcial part of the application I am working.

  15. #15
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    Don't give up hope. What you're trying to do is possible, either with one xml file per form, or one xml file for all of you forms. You have all of the building blocks. You just need to figure out how to fit it all together...

  16. #16

    Thread Starter
    Lively Member
    Join Date
    Aug 2017
    Location
    Brazil
    Posts
    87

    Re: Serialization of a Windows Form State - Help to refine the code

    Thank Paul. I am always of the position how things are possible to be made, essentially if I have not yet tried. So I have to sit down to study and figure out how.
    Thank you. Do you recommend any website, article to read about it? By the way, I really enjoyed you website "Inspirational Visual Basic.Net". I will look more often when searching for some new commands.

  17. #17
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    23,258

    Re: Serialization of a Windows Form State - Help to refine the code

    I can't recommend anything of an intermediate level except TechNet on MSDN. There you can find many articles, upload articles of your own, and enter your articles in the Monthly Guru Competition...

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width