-
Aug 22nd, 2018, 08:16 AM
#1
Thread Starter
Lively Member
[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
-
Aug 23rd, 2018, 12:16 AM
#2
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
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Aug 23rd, 2018, 08:29 PM
#3
Thread Starter
Lively Member
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?
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.
-
Aug 23rd, 2018, 08:30 PM
#4
Thread Starter
Lively Member
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?
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
-
Aug 23rd, 2018, 10:24 PM
#5
Re: Serialization of a Windows Form State - Help to refine the code
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Aug 27th, 2018, 12:07 PM
#6
Thread Starter
Lively Member
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.
I appreciate the help.
-
Aug 27th, 2018, 03:41 PM
#7
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...
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Aug 27th, 2018, 05:42 PM
#8
Thread Starter
Lively Member
Re: Serialization of a Windows Form State - Help to refine the code
Originally Posted by .paul.
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?
-
Aug 29th, 2018, 09:53 PM
#9
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
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Sep 2nd, 2018, 08:45 AM
#10
Thread Starter
Lively Member
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.
-
Sep 2nd, 2018, 08:58 AM
#11
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.
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Sep 2nd, 2018, 08:59 AM
#12
Thread Starter
Lively Member
Re: Serialization of a Windows Form State - Help to refine the code
Originally Posted by veronica.sa
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.
-
Sep 2nd, 2018, 09:02 AM
#13
Re: Serialization of a Windows Form State - Help to refine the code
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Sep 2nd, 2018, 09:09 AM
#14
Thread Starter
Lively Member
Re: Serialization of a Windows Form State - Help to refine the code
Originally Posted by .paul.
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.
-
Sep 2nd, 2018, 09:26 AM
#15
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...
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Sep 2nd, 2018, 09:38 AM
#16
Thread Starter
Lively Member
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.
-
Sep 2nd, 2018, 09:45 AM
#17
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...
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|