How to serialize a List in VB? - vb.net

I am writing a program to take several fields of a "patient" and serialize the data into XML. I am grabbing all the information as follows:
Dim pacients As New List(Of Patients)
Dim p As New Patients
p.mFirstName = txtFirstName.ToString
p.mlastName = txtLastName.ToString
p.mInsurance = txtInsurance.ToString
p.mDOB = txtDateOfBirth.ToString
p.mEmail = txtEmail.ToString
p.mPhone = txtPhone.ToString
p.mPlanID = txtPhone.ToString
p.mSubID = txtSubID.ToString
And this is the part with the big error (this is triggered by a different 'save all' button, where as the code before is part of a 'add to list' button):
Dim writer As New StreamWriter(PatientFileName.PatientFileName)
Dim serial As New XmlSerializer(GetType(Patients))
serial.Serialize(writer, pacients) 'in this line it just says there was an error generating the xml document
writer.Close()
If the patients class is required I will post it.

I found the problem. This:
Dim serial As New XmlSerializer(GetType(Patients))
Is expecting one object of patient, this needs to be changed to expect a list as follows:
Dim serial As New XmlSerializer(GetType(List(Of Patient)))
Thanks for all the suggestions.

This should do it... you can loop through your list and call this method each time, also make sure you have the serialize attribute at the top of your patient class, its required. Also your issue is because your gettype is for your patient class, not a list of patients which your passing in to serialize. Also from the looks of code you posted your don't need a list, just use your class object and save it...
Public Sub SavePatient(Byval patients As Patients)
Dim writer As New System.Xml.Serialization.XmlSerializer(GetType(patients))
Dim file As New System.IO.StreamWriter(
"YOURPATH.xml")
writer.Serialize(file, patients)
file.Close()
End Sub

Related

VB store list of records in a text file and read back

I have a VB program in VS2017. It reads many excel files and store relevant data in
Dim total_sessions As New List(Of Session_CSV_file)
The list is big (~10k), and includes about 20 fields each.
Is there a way in VB to store it in a file in one command and read it later on easily., without reading and writing each field?
Often I need to debug the later part. I prefer doing it without rerunning the whole first part.
Or is there a way in Visual Studio, to stop the run at a certain point, and store this point in a dump file, like simulators often do? (so they can run the simulation from this point later on)
Perhaps if you load your csv data into a DataTable instead:
Dim dt as New DataTable
dt.Columns.Add("Name")
dt.Columns.Add("Age", GetType(Int32))
For Each filepath in tenKFilePaths
For Each line in File.ReadAllLines(file)
Dim bits = line.Split(","c)
dt.Rows.Add(bits(0), Convert.ToInt32(bit(1))
Next line
Next filepath
Then you can save the whole lot to xml:
dt.WriteXml("c:\temp\my.xml")
Have a coffee, reboot etc the read them again and carry on where you left off:
Dim dt2 as New DataTable
dt2.ReadXml("c:\temp\my.xml")
Raw datatables are a bit difficult to work with because you end up accessing their rows and column data by string indexing and having to cast it a lot - fairly lame. There is a better way to use them, as visual studio can create custom classes that inherit from the base datatables and offer lots of functionality that does away with all the awkwardness of dealing with datatables as a very generic thing. Just like the forms designer creates a UI form that inherits from Form, the dataset designer creates custom datatables that inherit from the base
If you add a new DataSet type object to your project, double click it it opens something like a database designer. Right click that surface and choose Add DataTable, Add your Columns with their respective datatypes etc - this is the equivalent of your Session_Csv_File class, with its properties and fields. Double click on it and you can add code etc - if your session_csv_file has custom methods you can transfer their code to the custom data row
Imagine I created a new datatable in a DataSet and called it SessionCsvFiles. Imagine I added a Name and Age column, and I added a custom method called BlahBlah
I'd then be able to say in code things like:
Dim dt as New MyCustomDataSet.SessionCsvFilesDataTable
'it's like making a new SessionCsvFile
Dim r = dt.NewSessionCsvFilesRow()
'It's like setting your properties
r.Name = csvBits(0)
r.Age = Convert.ToInt32(csvBits(1))
'It's like adding your file to the List
dt.Add(r)
You now have virtually the same thing as you had before - a collection of objects that represents things about your csv files. The difference is with this route it has an already-built-in way of saving all the properties and the collection to xml and reading it back again
Add the Serializable attribute to the Class. I added a parameterized constructor for ease in building my list but you must provide a constructor without parameters for this to work. Thus, the empty Sub New.
<Serializable()>
Public Class Session_CSV_file
Public Property ID As Integer
Public Property Name As String
Public Property Type As String
Public Sub New()
End Sub
Public Sub New(SessID As Integer, SessName As String, SessType As String)
ID = SessID
Name = SessName
Type = SessType
End Sub
End Class
The add Imports System.Xml.Serialization to the top of the file.
Private Sub SaveList()
Dim serializer = New XmlSerializer(GetType(List(Of Session_CSV_file)))
Using writer As New StreamWriter("C:\Users\xxx\Documents\XMLtest.xml")
serializer.Serialize(writer, lst)
End Using
End Sub
I filled my list as follows but you can fill you list any way you choose.
Private lst As New List(Of Session_CSV_file)
Private Sub FillList()
Using cn As New SqlConnection(My.Settings.CoffeeConnection),
cmd As New SqlCommand("Select Top 10 * From Coffees;", cn)
cn.Open()
Dim reader = cmd.ExecuteReader
While reader.Read
Dim sess As New Session_CSV_file(reader.GetInt32(0), reader.GetString(1), reader.GetString(3))
lst.Add(sess)
End While
End Using
End Sub
To recreate the list... (OOps! forgot this)
Private RehydratedList As New List(Of Session_CSV_file)
Private Sub CreateListFromXML()
Dim serial As New XmlSerializer(GetType(List(Of Session_CSV_file)))
Using fs As New FileStream("C:\Users\maryo\Documents\XMLtest.xml", FileMode.Open)
RehydratedList = DirectCast(serial.Deserialize(fs), List(Of Session_CSV_file))
End Using
For Each item In RehydratedList
Debug.Print(item.ToString)
Next
End Sub

Update a table linked to a PowerPivot datamodel using EPPlus and it corrupts the datamodel

Using EPPlus I read an XLSX file.
I replace the data in a table and set the table range.
When I open the resulting spreadsheet I get an error:
"We found a problem with some content in 'MySpreadsheet.xlsx'. Do you want us to try to recover as much as we can?" -- I click Yes and I get another error:
"Excel was able to open the file by repairing or removing the unreadable content. Removed Part: Data store"
The error only happens after I add this table to a PowerPivot data model.
[EDIT] - I created a win forms app that reproduces this problem. You
can download it at here
I found the problem but don't know how
to fix it.
rename the xlsx to zip
Open the zip and browse to the xl\workbook.xml file
Look for the node collection.
Notice how EPPlus changes the <definedNames> collection to use absolute cell addresses.
Excel: <definedName name="_xlcn.LinkedTable_MyDate" hidden="1">MyDate[]</definedName>
EPPlus: <definedName name="_xlcn.LinkedTable_MyDate" hidden="1">'MyDate'!$A$2:$A$5</definedName>
If I modify this line after EPPlus is done saving then I can pull it
up in Excel without corrupting the Data Model.
I tried changing the WorkbookXml but it is happening when the
ExcelPackage.Save method runs.
For Each node In pck.Workbook.WorkbookXml.GetElementsByTagName("definedNames")(0).ChildNodes
node.innerText = "MyDate[]"
Next
Any ideas?
Try this first: create a spreadsheet with one table in it. Name the worksheet and table "DateList". Save it and run the below code on it -- it will work.
Then do this: open the same spreadsheet and add the DateList table to a pivottable data model. Save it and run the below code on it -- it will fail.
Here's some code from my MVC Controller -- only the relevant bits:
Public Class ScorecardProgressReportDatesVM
Public Property WeekRange As Date
End Class
Public Function GetScorecardProgressReport(id As Integer) As ActionResult
Dim contentType As String = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Dim DateList As New List(Of ScorecardProgressReportDatesVM)
DateList.Add(New ScorecardProgressReportDatesVM With {.WeekRange = CDate("Jan 1, 2015")})
DateList.Add(New ScorecardProgressReportDatesVM With {.WeekRange = CDate("Jan 1, 2015")})
Dim templateFile As New IO.FileInfo("c:\test.xlsx")
Dim ms As New IO.MemoryStream
Using pck As New ExcelPackage(templateFile)
ExtendTable(pck, "DateList", DateList)
pck.SaveAs(ms)
ms.Position = 0
End Using
Dim fsr = New FileStreamResult(ms, contentType)
fsr.FileDownloadName = "StipProgress.xlsx"
Return fsr
End Function
Private Sub ExtendTable(package As ExcelPackage, tableName As String, newList As Object)
Dim ws As OfficeOpenXml.ExcelWorksheet
ws = package.Workbook.Worksheets(tableName)
Dim OutRange = ws.Cells("A1").LoadFromCollection(newList, True)
Dim t = ws.Tables(tableName)
Dim te = t.TableXml.DocumentElement
Dim newRange = String.Format("{0}:{1}", t.Address.Start.Address, OutRange.End.Address)
te.Attributes("ref").Value = newRange
te("autoFilter").Attributes("ref").Value = newRange
End Sub
In order to fix this we had to change the EPPlus v4.04 source code.
ExcelWorkbook.cs # line 975 was changed
//elem.InnerText = name.FullAddressAbsolute; This was causing issues with power pivot
to
elem.InnerText = name.FullAddress; //Changed to full address... so far everything is working

How to create a new object in VB with a name taken from a variable

Good evening,
How do I create a new object in VB with the identifier/name taken from a variable.
Basically I want to pass a string (jobID) to a subroutine and in that I want it to create an object which is called whatever the string is.
So say jobID = "142sds2" I want it to effectively run dim 142sds2 as new object.
I have tried:
Public Sub newObject(jobID As String)
Dim jobID As New PhotoJob
End Sub
But this didn't work.
I'm relatively new to VB (but have a middling level of experience with C++ and Java) so any help would be appreciated, but please bare in mind my newness :P
Thanks in advance!
Use a dictionary:
Dim photoJobs As New Dictionary(Of String, PhotoJob)()
'...
photoJobs.Add(jobID, new PhotoJob())
Reference the created object like this:
photoJobs(jobID).SomeProperty
photoJobs(jobID).SomeMethod()
For Each job in photoJobs
job.Value.SomeMethod()
Next

How to get all forms in a VB.net (VS08) project in an array?

Alright, so I need a method that traverses all the forms inside a VB.net project under Visual Studio 2008, and create an array of type form with references to all the forms inside it, so that the array looks like this (pseudocode)
FormsArray() = [Form1, Form2, Form3, Form4]
However, I don't have a clue as to how to begin.
You have to adjust the function to put the result of msgbox in a array
Public Sub getallforms(ByVal sender As Object)
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In sender.GetType().Assembly.GetTypes()
If UCase(t.BaseType.ToString) = "SYSTEM.WINDOWS.FORMS.FORM" Then
MsgBox(t.Name)
End If
Next
End Sub
You must call the function from any form in the application like this (getallforms(me))
Here is how you would do this using Reflection, assuming that the class where you placed this code was in the same assembly that you wanted to iterate over. If not, then you'll need to change the Me.GetType().Assembly in the For Each loop into something else to account for loading the assembly in a different manner.
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
Hey this is what I did to get the list of forms in my vb project, how ever this in not in code but you could write system.io code fragment to do just that.
open cmd prompt
go to project folder
run a dir /s/b *.designer.vb >> list.txt
use notepad or sublimetext and edit it to get the list ordered as you like it.
:) hope this helped!
I could not get this version to work:
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
In VB2010 formType is always Nothing
So I dumped the formType line and simply modified your 'IF' statement to check the BaseType instead. Here is the New Version
Dim Forms As New List(Of Form)()
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.BaseType.Name = "Form" Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
You need to either write a VS macro or an Addin.
In it, from a DTE or DTE2 instance, you can write:
Public Sub GetForms(ByVal host As DTE2)
Dim project As Project = host.ActiveDocument.ProjectItem.ContainingProject
For Each ce As CodeElement In project.CodeModel.CodeElements
If ce.Kind = vsCMElement.vsCMElementClass Then
Dim cl As CodeClass = CType(ce, CodeClass)
If cl.IsDerivedFrom("System.Windows.Forms) Then
'do something
End If
End If
Next
End Sub
2 options
I would load the actual project file into a XML reader. Then iterate all the nodes looking for all Form SubTypes and store the linked files in an array. If the name of file matches the name of the form class, you can create your FormsArray from that list. Otherwise you have to load each file and look for the public class definition of the file to get the list.
Using Reflection, examine the project using Assembly.GetTypes. Find all the System.Windows.Forms.Form Types and store them in a list. Then write out the Type.Name.

How to do Mailmerge in Openoffice using Vb.net

Its 5th Question and apart of one I didn't get response from the experts....
Hope this time I will get the helping hand.
I want to do mailmerge in openoffice using Vb.net and I am totally new with openoffice.
I searched on net for some help to understand how to use openoffice with vb.net but all I get is half info.....So can you please help me and give me code for mailmerge in vb.net for openoffice.
Well i have list of workers in DB and there is this facility that if they want to mail to all or some of the workers then they can do it.I have completed this task using Microsoft Office now as a Add in we are providing the facility to perform the same task using Open Office.
What they have to do is just select the List of workers and click on a button and it will automate the mailmerge using the field of those workers data from DB. The Code of mine is as shown below
Public Sub OpenOfficeMail(ByVal StrFilter As String)
Dim oSM ''Root object for accessing OpenOffice from VB
Dim oDesk, oDoc As Object ''First objects from the API
Dim arg(-1) ''Ignore it for the moment !
''Instanciate OOo : this line is mandatory with VB for OOo API
oSM = CreateObject("com.sun.star.ServiceManager")
''Create the first and most important service
oDesk = oSM.createInstance("com.sun.star.frame.Desktop")
''Create a new doc
oDoc = oDesk.loadComponentFromURL("private:factory/swriter", "_blank", 0, arg)
''Close the doc
oDoc.Close(True)
oDoc = Nothing
''Open an existing doc (pay attention to the syntax for first argument)
oDoc = oDesk.loadComponentFromURL("file:///C:\Users\Savan\Documents\1.odt", "_blank", 0, arg)
Dim t_OOo As Type
t_OOo = Type.GetTypeFromProgID("com.sun.star.ServiceManager")
Dim objServiceManager As New Object
objServiceManager = System.Activator.CreateInstance(t_OOo)
Dim oMailMerge As New Object
oMailMerge = t_OOo.InvokeMember("createInstance", Reflection.BindingFlags.InvokeMethod, Nothing, _
objServiceManager, New [Object]() {"com.sun.star.text.MailMerge"}) 'com.sun.star.text.MailMerge"})
oMailMerge.DocumentURL = "file:///C:\Users\Savan\Documents\1.odt"
oMailMerge.DataSourceName = CreateSource(StrFilter)''Function that will return the datasource name which will be a text file's path
oMailMerge.CommandType = 0
oMailMerge.Command = "file:///C:\Mail.txt"
oMailMerge.OutputType = 2
oMailMerge.execute(New [Object]() {})**---->I am getting Error here**
End Sub