How to serialize and deserialize a form? - vb.net

How do I serialize and deserialize my main form (and its controls, subcontrols, their values, etc.)?
Edit, for clarification. Currently I am writing the current value of each control to an .INI file, one by one and reading it back when the program is next run. Every time I add a new control, I have to remember to update that save/load .INI code.
I just wondered if I can do it in one call, or a simple for loop iterating over all controls on the form.
Btw, I use only simple controls like edit box, radio button, combo box, checkd listbox, the most complex thing I have is a datagrid, but even that is not linked to a databse.
Accepted answer "can't. I will probably code my own, along the lines of ...
for each child control (recursivley)
if conrol is editbox ...
if control is radiobutton ...
if ... etc
write control name to .ini file
write control "value" to .ini file
maybe later add left/top/height/width/enabled/visible, etc, bu tfor not th econtrol name an its "value" are enough (text, value, lines, checked?, etc)

There's no out-of-the-box support for serializing .NET forms and controls. Controls are not marked with the [Serializable] attribute.
I think most of the difficulty revolves around .NET controls that are really wrappers of native Win32 controls. Persisting the native state as XML, it seems, would be infeasible.
Perhaps someone has written a custom serializer; if not, you may need to roll your own.
Edit:
I found this discouraging accepted answer on experts exchange:
You have to implement ISerializable
or IXmlSerializable in order to do
something like that (depending on how
do you want to serialize the form).
It's not trivial.

Serializing the entire control sounds like a difficult proposition. However, if you want to serialize the data within that control, that's certainly possible, assuming you have it structured decently well.
For example, let's say you have a Person object with a List of Address for your AddressBook application:
Public Class Person
Public Property PersonName As String
Public Property PersonAge As Integer
Public Property Addresses As New List(Of Address)()
End Class
Public Class Address
Public Property StreetAddress As String
Public Property City As String
Public Property State As String
Public Property Zip As String
End Class
If you bind this data to your form, you can easily serialize and deserialize it to and from XML. To serialize:
Imports System.Xml.Serialization '<==you need to import this namespace '
'...'
Dim thisPerson As New Person()
Dim serializer = new XmlSerializer(thisPerson.GetType())
Using writer = XmlWriter.Create("thisPerson.xml"))
serializer.Serialize(writer, thisPerson)
End Using
To deserialize:
Dim thisPerson As New Person()
Dim serializer As New XmlSerializer(thisPerson.GetType())
Using reader = XmlReader.Create("thisPerson.xml")
thisPerson = CType(serializer.Deserialize(reader),Person)
End Using
I learned about XML Serialization from this answer to a question I had previously asked.
Granted, if you're manually loading/extracting data from your forms, this isn't going to work. I good idea might be to encapusate your underlying data for a form in a class and then bind that class to the form. This way, you can easily serialize/deserialize the data in the form.

Related

Listbox DisplayMember from nested object VB.net

I have a class called ComponentTransactionPair, it houses two objects called m_Component and m_Transaction, there is a public property
Protected m_componentTransactionPair As List(Of ComponentTransactionPair)
In trying to hook this to a ListBox I am using the code below
lstbCurrentTransactions.DataSource = m_componentTransactionPair
m_currentOptionsLoaded = True
lstbCurrentTransactions.DisplayMember = "m_Transaction.Description"
The DisplayMember is not working properly for me in doing this and i'm pretty sure it's displaying the type rather than the Description property within the Transaction.
Is it even possible to use a nested object's property to get this category here because everything I've seen does not use a nested object.
Fixed this by just adding another property to the class and took it from the value I needed. Worked perfectly afterwards. If there's a less hacky solution i'd be interested to hear it though.

How to access buttons on a parent form from a child form which inherits it

I made a Windows Form in VB.NET that has a Panel with a Datagridview on it, and underneath it a FlowLayoutPanel with Save and Close buttons on it, call it frmParent. Then I created frmChild and on it I inherited frmParent. I then hooked up my DataGridView to some data and it worked fine.
Next I tried to add code to save changes to the datagrid and the buttons are locked. I checked the modifiers: both buttons and the FlowLayoutPanel that contains them are Protected. I read that there are frequently problems accessing controls that are contained in a collection of another control. But the DataGridView is fine, so my question:
What do I need to do to get the Save and Cancel buttons to be available on the child form? Do I need to do away with the FlowLayoutPanel, or is there another way? In this simple example it isn't that big of a deal, but I would like to start using visual inheritance regularly and I would like to know the best way to do things.
Something like this ?
Public Class frmParent
Private Sub Button_SaveClick(sender As Object, e As EventArgs)
ButtonSaveClicked(...) ' pass here any argument you want (e, sender, anything...)
End Sub
Protected Overridable Sub ButtonSaveClicked(...)
' Do here what frmParent should do upon Button_Save Click...
End Sub
End Class
Public Class frmChild
Inherits frmParent
Protected Overrides Sub ButtonSaveClicked(...) ' same arguments
' Do here what frmChild should do upon Button_Save Click...
' Eventually call MyBase.ButtonSaveClicked(...)
' if you want frmParent to act aswell...
End Sub
End Class
EDIT : For the following parts of the question :
dissociating user interface and object datas
passing an instance of the object or not ?
I'm no expert on programming, but I've read one interresting thing about that user interface/object.
What come to my mind first talking about user interface is a blog post (don't recall the link, sorry) talking about Windows way of programming and Linux way. Before starting to drift to an off topic ride, I want make clear that I don't care about linux vs windows and I'm not interrested in such debate. Just want to share what I remember from this blog post :
In windows programming, the first thing you usually think of (and invited to do) is to create an user interface : the windows form (or the window in WPF) Then you'll create the objects that will be manipulated through that interface. In linux programming, it's the inverse : you'll create first the objects with everything they should be able to do, and only after you'll think of the user interface that will "enhance" the way to manipulate them.
^^ Or alike.. I'm zero linux knowledge, so I can't compare, but I assume the above is true, mostly. And I reckon that since OOP existed, this "windows way" of programming (that I'm used to) has a lot of drawbacks and messy code : you're constantly asking yourself wether a specific part of the code should be enclosed in the object or in the user interface.
So, I've come to an idea of mine, it may be stupid, but I'm fine with. I started to try that "linux way"... at least, "the way I'm thinking a linux programmer does it"
Let's take that control called DataGridView. It can contain text, dropboxes, buttons, images, etc. I'm not digging in bounding Dataset to keep it simple. Basically, the DataGridView is an object having everything to manipulate the above sub-objects within it. Unfortunately, a String, or an Image is not a (visual) control, while a dropbox, or a button is. You have a typical case of windows created object (DataGridView) that is a melting pot of datas and user interface, but you don't have an object that handles only the data part of the DataGridView, and another object that handles only the visual user interface of the thing (or at least, I'm not aware of such objects in .Net) AFAIK You're forced to handle both data and user interface when using a DGV !
So I created a class and simply called it Table_Class that can contain such objects (that are not controls) like String, Bitmap, List (of String), XML... almost anything as the contained datas are binary coded.
Then I created a Form, and called it Table_Form, that can display the content of a Table_Class. But almost all edits are functions and methods that are members of the Table_Class. If I want to order the grid by columns, it's the class that does it through one of its inbuilt function.
Of course, I'm not here to show that I'm wasting my time to reinvent the wheel, I know I'm doing it wrong but this approach is required by the fact I'm dealing with a massive amound of various datas loaded from files and saved as files. I'm just glad I have my own class of datas and happy to extends its capabilities when I want.
The main purpose of this blabla is to illustrate my opinion about passing an entire class or some of its members to a form. In this tandem Table_Class/Table_Form, of course, I'm passing the entire Table_Class on the Table_Form and vice versa. In fact, it's two different thing that can be used at the same time, or one at a time :
' SAMPLE CODE : Entire classes takes several files...
Public Partial Class Table_Class
' here is the object that is invisible to the user
Private _ContainerForm As Table_Form = Nothing
Public Sub ShowForm(Optional ByVal OwnerForm As Form = Nothing)
If _ContainerForm Is Nothing Then
_ContainerForm = New Table_Form(Me)
End If
If OwnerForm Is Nothing Then
_ContainerForm.Show()
Else
_ContainerForm.Show(OwnerForm)
End If
End Sub
Public Sub New()
End Sub
Public Sub New(ByRef NewContainerForm As Table_Form)
_ContainerForm = NewContainerForm
_ContainerForm.SetTable(Me)
End Sub
End Class
And here is the (associated) Form (constructor and associated Object initialization)
Public Partial Class Table_Form
Private _SelectedTable As Table_Class = Nothing
Public Sub SetTable(ByRef NewTable As Table_Class)
RemoveHandlers() ' Table_Class has events.
' If _SelectedTable is not Nothing,
' remove handlers prior to redefining a new selected Table.
_SelectedTable = NewSelectedTable
_SelectedTable.SetContainerForm(Me)
InitializeHandlers() ' Add all handlers for UI updates upon Table_Class edits.
End Sub
Public Sub New()
End Sub
Public Sub New(ByRef NewSelectedTable As Table_Class)
SetTable(NewSelectedTable)
End Sub
End Class
As you can see, I can manipulate the Table_Class either in the background when the user shouldn't care about its content, or via a user interface. With a DataGridView, you must take care of all the visual appearance in order to build an output to the Data/DataSet/Database.
What is important to note here is from the moment you want a visual display of an object through an user interface, you MUST pass critical members of that object to the displaying interface. You can't avoid doing it at a moment or another. In my example, I've passed the ENTIRE Table_Class since I'm doing every data modification in that class.
The difference with a DataGridView is :
with a DGV, when you edit one (String) entry in a Cell using KeystrokeOrF2, the Value is stored in that Cell of that DGV, then, either your application directly sends programatically the value to the associated Database, either you have a save button or a save menu to update the edits.
With my Table_Class, of course I'm using a DataGridView to display its contents, and I have a save button on a toolbar and in a menuitem. But when I click on those buttons, the Save method is not in my Table_Form Form. The Save Method is a method belonging to the Table_Class itself.
That's an example where lies the separation between the visual interface (of the DataGridView/Form) and the object actually containing the datas.
I know this Table_Class/Table_Form example is a complex one, but the way I understand half of the secund part of your question in your original post is : "how do I separate user interface and data/object manipulation"
The answer : it's up to you !
I think we have similar ways of doing it : my Table_Class does everything as your BlackBox Class. My Table_Form shows the datas and your Parent/Child Form so does.
I assume the remaining half of your issue is : "I can't call BlackBox.SaveChanges from the Click method of my button when it is in the FlowLayoutPanel". That's not related to the Object/User Interface limits syndrome, and is an entirely different issue. That's the main purpose of this answer before this long edit : I suggested a workaround by calling a method (ButtonSaveClicked()) instead of writing the save part of the code direclty under the Button_SaveClick() method that handles the click. I don't know if this approach worked for your "locked" button or not.
Back to the user interface/object thing : So comes the above : "you must pass critical members of your object to the user interface at a certain point", and that critical member must be an object (with the critical datas you want to manipulate, in this case, I assume the data to save) In my Table_Class/Table_Form example, I've passed the entire Table_Class in the Table_Form :
Public Partial Class Table_Form
Private _SelectedTable As Table_Class
' ...
End Class
so when I want the Table_Class (object containing data to manipulate) to save edits, through the table Form (form acting as an user interface) I have those methods sets in the Form :
Public Partial Class Table_Form
Private Sub Menu_Main_File_SaveClick(ByVal sender As Object, ByVal e As EventArgs)
' MenuStrip -> File -> Save
SaveTable()
End Sub
Protected Sub ToolBar_Main_SaveClick(ByVal sender As Object, ByVal e As EventArgs)
' A Save Button shortcut on a toolbar.
SaveTable()
End Sub
' ^^ Both controls calls the same method SaveTable()
' This is similar to the ButtonSaveClicked method I initially suggested
' What SaveTable does ?
Protected Overridable Sub SaveTable()
If _SelectedTable IsNot Nothing Then
_SelectedTable.Save(True)
End If
' It just calls the Table_Class.Save(... arguments)
End Sub
' ...
End Class
In the end, the code handling how the datas should be saved doesn't exists in the user interface. To save changes, the Table_Class object has a handfull set of Save(...) methods that handle extension like SaveAs (opens a SaveFileDialog), Overwrite without Prompt, Save as binary or save as textual... And if I want more extensions like sending the datas on the web, in a database, or even packing/unpacking the table contents in a directory, all I have to do is to implement that in the Object (Table_Class) and only the visual part will be handled in the form, the same way I did it from the start.
So when you ask me "Wouldn't I end up with child-specific code in the parent form that way?" I would say : "it's up to you". I've decided that the Table_Class does everything : data loading/parsing, data updating and data saving. If at a time in the future I have to implement a new way of saving the datas, I have the choice to add an overload of the Save() method of my Table_Class, or building a specific Save method in another form for another application using my Table_Class if I want. And that's possible because the Table_Class :
is not an User Interface
has an associated user interface in case it's required
while it has everything to read from and write datas to, programmatically.
and yes, I'm passing the entire Table Class in the UI, no matter it's a parent one or a child form that use inheritance.
I think "having messed parent/child code in your user interface side" highly depends on the capabilities of your non user interface object that (should) manipulate the datas.
(Actually, the Table Class is not a single Table. It's the Node of a Tree of Tables, or a Table that contains datas, and Tables children that contains other datas each. You can think of it like the merger of a DataGridView and a TreeView, that's why the Private variable un the UI Form is named _SelectedTable.)
I'm mentioning that last complexity of the Table_Class to clearly notify that no matter how complex the object is, it's easy to use whatever the user interface you use, because there isn't a single visual code in the object, and there is very little code manipulating datas in the user interface (all the UI does is to read datas from the object, display/edit or use them for other purposes, and send the validated modifications to the object, then call Object.Save())
I've made a long explaination of the way I'm doing it to let you have the latitude to decide how you want your application to behave, what your BlackBox class should be able to achieve alone and what are the limits of your user interface. There is no simple answer to that analysis, and highly depends on who is going to use your application for what purpose; if you have deadlines, keep it simple, but if your goal requires complex and highly manipulable datas, I think you should not mix user interface code and data manipulation code; this is a hell to alter if you have to upgrade your class with new features at a later time.
Sorry for the long post. I'm french speaking and I don't know if my english is okay. Don't mind the blabla, that's just me, can't keep an idea in my mind without telling it in details.
Try the ButtonSaveClicked() call workaround. That worked for me with a flow layout panel : I've made an Overridable ButtonSaveClicked() in the parent Form with a message box saying "Hello", and an Override ButtonSaveClicked() in the child Form saying "Coucou", and it worked well.
Then you can create a variable containing your BlackBox object in the parent form like I did with my Table_Form, and a way to make it accessible from the child form (Protected, or Public Property or a set of Protected methods and functions, I don't know...) Then decide what would be your BlackBox members (properties, methods, functions, events...) and how they should/could be used from the parent and the child forms.
To expose an action on a base class control as an event (another answer shows how to do this via an overridable method):
Base Form:
Public Event SaveClick As EventHandler
Protected Overridable Sub OnSaveClick(ByVal e As EventArgs)
RaiseEvent SaveClick(Me, e)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
OnSaveClick(e)
End Sub
Child Form:
' the event will show up in the event list like any other
' this may be what you want if each child form is supposed to do everything
Private Sub Form1_SaveClick(sender As Object, e As EventArgs) Handles Me.SaveClick
' save some stuff
End Sub
' hybrid where the child form does some stuff, base form does some stuff
Protected Overrides Sub OnSaveClick(e As EventArgs)
MyBase.OnSaveClick(e) ' base form activities
'save some stuff
End Sub
So the base form could raise some abstracted events like SaveItem, NewItem, DeleteItem and the child forms act on that much like how an interface works.
The flaw in this approach is that the controls are still locked on the BaseForm, as they should be (controls are Friend). Each child could pass a parameter to the base form indicating a "mode":
Public Sub New()
MyBase.New("Customer")
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
But to make use of it means that the base form has to have logic to handle all those various "modes" which negates the value of inherited forms specialized to handle Foo, Bar, Customer etc. So, I am not sure form inheritance is what you want: the controls described seem too specialized.
Your best bet, both from a functional standpoint and design standpoint, is to create events in your child form, i.e. OnSaveRequested and OnCancelRequested. In your parent form, declare your child form using WithEvents and create handlers for those events. When you want to save from the child form, raise the OnSaveRequested event and handle it in the parent form (same with Cancel).
Of course, in this scenario your parent form will need to know what to save, so you can either pass the data in as an argument to the event or expose a public property to the data in your child form.

Is there a way to pass values between forms in vb.net? (Without using a public variable)

I have an application that uses a second form with textBox and button, and i need to pass the text from textBox to the first form. I know how to do it with a public variable, but i would like to know if there is another way to do it without using a public variable.
Yes!
If the forms are part of the same solution, you simply write:
Dim MyVal1 As Integer = Form2.MyVal
MyVal1 exists in whatever form you write it in, and MyVal2 comes from Form2. These variables can only be shared if the forms have the right privacy settings.
If the two forms are part of separate applications, the only way i know of passing variables around is through constructors.
EDIT:
In your case with a textbox, you may be able to apply similar a solution:
Dim val As String = Form2.TextBox1.Text
You can use PUBLIC properties on the second form to read/write info to the other form.
You can overload the NEW method to pass variable during declaration.
You can create a public sub/function on the second form and pass variable byval or byref.
But, I would NEVER use a public variable. That is bad programming.

Best design method for Printing labels

Currently, I have a UI where the user chooses a product from a list. When they double click on the product of their choice another form shows the product with some additional information as well as the associated bar code. On this second form there is a print button. (This is where my question is) When the print button is clicked I want send this information to a Label Template and viewable (probably though a PrintPage) and then be able to be sent to a printer from that.
What is the best way to accomplish this? I can think of two different ways to accomplish this but I'm sure there are better ways out there.
1) I can create the template in XAML and then databind to the form
2) I can create the template in the form.vb 's _PrintPage event. (most straightforward but not the fastest)
Is there an easier way to create the template and send the information to it and then print the template?
It would be easier to just make another windows forms and design the template that way, but is it possible to send this form to a print object at runtime?
Typically anything I have to print, like labels, I use a reporting tool. .Net comes with its own Microsoft Reporting Tool, http://msdn.microsoft.com/en-us/library/bb885185.aspx, and there are lots of third party report tools like Crystal or Telerik. They all have visual designers for layout and handle all the print preview and printing stuff for you.
If I understand you correctly you want to control the process within your own program without using report tools? In that case I will list some thoughts about one implementation -
You can make a simple template functionality using (a serializable) dictionary that contains regions and region types. As you work with an absolute area (the label itself) you can for example do this:
Private Template as Dictionary = New dictionary(Of String, TemplateEntry)
Friend Class TemplateEntry
Public MeasureType As MeasureType
Public RegionType As Regiontype
Public X As Single
Public Y As Single
Public Width As Single
Public Height As Single
Public Content as Object
End Class
Friend Enum MeasureType
Centimeters
Millimeters
Inches
Pixels
'...
End Enum
Friend Enum RegionType
Text
[Image]
BarCode
'...
End Enum
Then in you code you convert the x,y,w,h into pixels based on the DPI and return a Rectangle for example. You can XML Serialize the dictionary to create other templates and so forth.
The Content field is initialized when parsed.
To add you could do for example:
Dim tmpl As TemplateEntry = New TemplateEntry
tmpl.MeasureType = MeasureType.Millimeters
'...
Template.Add("Barcode", tmpl)
Then "render" the template into your canvas for printing:
For Each tLine in Template
Dim r as rectangle = CalcMeasuresIntoPixels(tmpl)
'...
' render each element based on type and location
Next
Hope this gave some input.

How to run a string as a command in Visual Basic (VB.NET)

i am running a Sub which takes as arguments a Datatable and a String.
Private Sub Populate(ByVal dttemp As DataTable, ByVal strWhichPart As String)
At one point there is a combobox which is populated with some of the data in the datatable. The name of the combobox is cmd plus the name of the string for example when the string is Person_FirstName the name of the combobox is cmbPerson_FirstName. Then i add items to the combobox like this:
cmbPerson_FirstName.Items.Add(strHold(rr))
My question is this can i make a String into a command? Because i have many comboboxes which have the same name as the string argument of the sub how can i do something like this to work
strWhichPart.Items.Add(strHold(rr))
in which strWhichPart is a string. Is there a command that i can execute a string as a command?
Thank you.
If I understand correctly, just grab the correct control from the Form's Controls collection using the string as the key:
CType(Controls(strWhichPart), ComboBox).Items.Add(strHold(rr))
You can use reflection to achieve this by creating an assembly with the code in a method, but its really not recommended. As in, it's insane. I suspect there are no problems in .NET development that need this approach.
Rather than using this approach, actually pass the relevant combo box as an argument - not an arbitrary string. Combo boxes are objects like anything else. You could create a dictionary which allows you to lookup combo boxes by a string. Something like:
Dictionary(Of String, ComboBox) MyDictionary = new Dictionary(Of String, ComboBox)()
MyDictionary.Add("ComboBoxA", objComboBoxA)
ComboBox objTheComboBox = MyDictionary("ComboBoxA")
The name you give your objects should not be semantically relevant in your code. If I name an object "lstMyObjectNamedThisWayForAReason1" I should NOT be using that to reference it. Instead, there should be a separation between what constitutes a GUI element and how it is referenced.
For example, if I create a WinForms GUI and reference all the items directly, then later have to write another front-end using a different framework I have to rewrite every reference. This isn't a problem if you don't tie your logic directly into your controls.
The only reason to tie them together is laziness and lack of respect for co-workers who might have to improve on your code in future. Why should they care what the GUI looks like? They might not even be using Visual Studio! They certainly can't take your code and use it elsewhere without ripping out your GUI dependency.
With a minor modification of ho1 it worked. Thanks a lot
CType(Controls("cmb" + strWhichPart), ComboBox).Items.Add(strHold(rr))