I'm using Visual Studio 2019 with VB.NET. The goal is to dynamically write an xml file to a field in my SQL database. I've got various DataGridViews where the user can enter rows of information. The goal is to write this info to an XML file. I'm using an an XmlTextWriter to write the file to a MemoryStream since I don't want to actually write the file. I then try to Serialize the file and store it to an XML column in the database. The problem is my Serializer is returning nothing.
Here is the code:
Public Function CreateDgvXml(dgv As DataGridView) As String
Using ms As New IO.MemoryStream
Dim xtw As New Xml.XmlTextWriter(ms, Text.Encoding.UTF8)
Dim fn() As String = MapFieldNames(dgv)
With xtw
.WriteStartDocument(1)
.WriteStartElement("dgv")
.WriteAttributeString("name", dgv.Name)
For Each row As DataGridViewRow In dgv.Rows
.WriteStartElement("row")
For Each cell As DataGridViewCell In row.Cells
.WriteStartElement(fn(cell.ColumnIndex))
.WriteString(cell.FormattedValue.ToString)
.WriteEndElement()
Next
.WriteEndElement()
Next
.WriteEndElement()
.WriteEndDocument()
End With
Dim xs As New XmlSerializer(GetType(clsNewQuote))
xs.Serialize(ms, New clsNewQuote)
xtw.Flush()
Return xs.ToString
End Using
End Function
Private Function MapFieldNames(dgv As DataGridView) As String()
Dim result(dgv.ColumnCount - 1) As String
For Each col As DataGridViewColumn In dgv.Columns
result(col.Index) = col.HeaderText
Next
Return result
End Function
'''
Does anyone know how to do this properly?
Related
I'm trying to add "file type" and "last modified" to my Listview when adding items in It same as in Explorer, but I don't find what property should be assigned to SubItem. Here is my code:
For Each MyFile As IO.FileInfo In ItemDirectory.GetFiles
Dim lvi As New ListViewItem
lvi.Tag = mFile.FullName
lvi.Text = mFile.Name
lvi.ImageKey = CacheShellIcon(mFile.FullName)
Listview1.Items.Add(lvi)
lvi.SubItems.Add("File type ??")
lvi.SubItems.Add(mFile.LastAccessTime.ToShortDateString & " " & mFile.LastAccessTime.ToShortTimeString) 'This isn't same as last modified ?
Next
If somebody knows how to do It please let me know, I want to have this in my Details view.
The linked answer provides an all-purpose way to get all the extended properties. With 300+ elements in newer Windows versions it is clearly overkill to fetch them all if you are only interested in one or two. This returns just the file type. A better approach might be to pass a "shopping list" of desired property names.
As before, you need to add a reference to Microsoft Shell Controls and Automation or Microsoft Shell Folder View Router based on your OS version.
Imports Shell32
Imports SHDocVw
Partial Friend Class Shell32Methods
Friend Shared Function GetShellFileProperty(filepath As String, index As Int32) As String
Dim shell As New Shell32.Shell
Dim shFolder As Shell32.Folder
shFolder = shell.NameSpace(Path.GetDirectoryName(filepath))
' get shell data for this file, cast to folder item
Dim shFolderItem = DirectCast(shFolder.Items().Item(Path.GetFileName(filepath)),
Shell32.ShellFolderItem)
If shFolderItem IsNot Nothing Then
Return shFolder.GetDetailsOf(shFolderItem, index)
Else
Return String.Empty
End If
End Function
...
End Class
Usage:
Dim lvi As ListViewItem
Dim fileType As String
For Each f As String In Directory.EnumerateFiles("C:\Temp\ShellTest")
fileType = Shell32Methods.GetShellFileProperty(f, 9)
lvi = New ListViewItem
lvi.Text = Path.GetFileName(f)
lvi.SubItems.Add(fileType)
lvFiles.Items.Add(lvi)
Next
Ideally, you'd want to create an Enum for the properties so the code could avoid magic numbers:
fileType = Shell32Methods.GetShellFileProperty(f, Shell32FileProps.FileType)
As noted elsewhere, the index of the ones >260 or so can change depending on the OS version. That could be easily modified to accept an Enum/Int array and return a list of values so as to prevent iterating all 300+ propertied to get one or three.
For filetype you can use lvi.SubItems.Add(MyFile.Extension)
and for the "last modified" date, of course the last modified! :D
lvi.SubItems.Add(MyFile.LastWriteTime.ToShortDateString)
Last write and last access are not the same ;)
I figured out another solution, I think this one is easier, at least for me :
Public Function ExProperty(filepath As String, PropertyItem As Integer)
Dim arrHeaders As New List(Of String)()
Dim shell As New Shell
Dim rFolder As Folder = shell.[NameSpace](Path.GetDirectoryName(filepath))
Dim rFiles As FolderItem = rFolder.ParseName(Path.GetFileName(filepath))
'I needed only File type so I looped to 2 only (2 is the file type in my case - Windows 10 -
' to see all available properties do a loop
' 0 To Short.MaxValue - 1" and then extract whatever property you like)
For i As Integer = 0 To 2
Dim value As String = rFolder.GetDetailsOf(rFiles, i).Trim()
arrHeaders.Add(value)
Next
Dim DesiredProperty As String
DesiredProperty = arrHeaders.Item(PropertyItem)
Return DesiredProperty
End Function
Usage with Listview just simply (this adds File type subitem):
Listview1_Item.SubItems.Add(ExProperty(filepath, 2))
As in all solutions, a reference to Microsoft Shell Controls and Automation must be set.
i have a user interface form that let's you upload a text file to a datagridview as follows
Sub Datagrid()
Dim sw = System.Diagnostics.Stopwatch.StartNew()
Using stream As System.IO.FileStream = System.IO.File.OpenRead(TextBox1.Text)
Using reader As New System.IO.StreamReader(stream)
Dim line As String = reader.ReadLine()
While (line IsNot Nothing)
Dim columns = line.Split(";")
line = reader.ReadLine()
Dim index = Me.DataGridView1.Rows.Add()
Me.DataGridView1.Rows(index).SetValues(columns)
End While
End Using
End Using
sw.Stop()
End Sub
Well, now my problem is that i don't want to put the full txt file in that datagridview, just from line N.
Is it possible to do that? Like creating a querytabel and selecting a fixed value?
p.e., in line 5 there's always the text "Values:" . Can i select all the lines after that to put in the datagridview? i googled everywhere but found nothing. and there's no "sample" code to give me a start . thank you all !
Dim n As Integer = 5
Dim lines As IEnumerable(Of String) = IO.File.ReadAllLines("textbox1.text").Skip(n)
'Gets every line after a certain line count
'Create a new datatable and add some columns
Dim dt As New DataTable
dt.Columns.AddRange((From columnIndex As Integer In Enumerable.Range(1, lines.First.Split(";"c).Count) Select New DataColumn("Column" & columnIndex.ToString())).ToArray())
'Add each line as a row to the datatable
For Each line As String In lines
dt.Rows.Add(line.Split(";"c))
Next
'Set the datasource of the datagridview
MyDataGridView.DataSource = dt
I am able to write to the file perfectly... however I am having trouble reading from file and inserting read data into a listbox.
Public myData As New MySettings
Public saveFile As String = ("mysettings.ini")
'SAVE INFO TO SETTINGS FILE
Dim fs As Stream = New FileStream(saveFile, FileMode.Create)
Dim bf As BinaryFormatter = New BinaryFormatter()
For l_index As Integer = 0 To ListBox1.Items.Count - 1
Dim l_text As String = CStr(ListBox1.Items(l_index))
bf.Serialize(fs, l_text)
Next
fs.Close()
Return
This is the part where I am having trouble...
'LOAD INFO FROM SETTINGS FILE
Dim fs As Stream = New FileStream(saveFile, FileMode.Open)
Dim bf As BinaryFormatter = New BinaryFormatter()
For l_index As Integer = 0 To saveFile.Count - 1
Dim l_text As String = CStr(saveFile(l_index))
'myData = CType(bf.Deserialize(fs), CType(myData))
ListBox1.Items.Add(myData)
Next
fs.Close()
Return
Any help at all would be appreciated, even a point in the right direction.
Thanks in advance!!
The ListBox ObjectCollection (Items) is not marked as serializable, so you cant serialize the entire thing at once. You may have encountered this and used the loop to serialize each item. The loop does appear to serialize each item, but I don't know how you can deserialize in a loop - you wont know how many items there are, nor will the Serializer.
Rather than one item at a time, you could copy the ListBox items to an array and serialize the entire thing:
Dim ary(lb.Items.Count - 1) As Object
lb.Items.CopyTo(ary, 0)
' OpenOrCreate!
Using fs As New FileStream("C:\Temp\lbitems.bin", FileMode.OpenOrCreate)
Dim bf As New BinaryFormatter
bf.Serialize(fs, ary)
End Using ' close and dispose of stream
Deserialization is just the reverse:
Using fs As New FileStream("C:\Temp\lbitems.bin", FileMode.Open)
Dim bf As New BinaryFormatter
Dim myAry = bf.Deserialize(fs)
lb.Items.Clear()
lb.Items.Add(myAry)
End Using
You can make it a bit simpler using a List(of String) and assign it as the DataSource.
Private myLBItems As New List(Of String)
...
' fake items to add
myLBItems.Add("Foo")
myLBItems.Add("Bar")
myLBItems.Add("Option")
myLBItems.Add("Strict")
lb.DataSource = myLBItems
Using the List as the DataSource, you dont have to copy items from here to there - whatever is in the List will appear in the ListBox. Serialization is simple too:
bf.Serialize(fs, myLBItems)
Since Deserializing returns an Object, you need to cast it (Option Strict):
myLBItems = CType(bf.Deserialize(fs), List(Of String))
Note: This may not be doing what you want at all. Your code is serializing what is in the ListBox after converting it to String. Later, it looks like you want to Deserialize to a MySettings Type.
If MySettings is something like a Name and Value pair (or collection of them), probably half the data and all the Type information will have been lost.
I'm working on a Timer program, that allows the user to set up a timer for each individual user account on the computer. I'm having some trouble writing the settings to a text file and reading from it. I want to know if it's possible to write it in this fashion --> username; allowedTime; lastedLoggedIn; remainingTime; <-- in one line for each user, and how would I go about doing that? I also wanted to know if it's possible to alter the text file in this way, in the case that there's already an entry for a user, only change the allowedTime, or the remainingTime, kinda just updating the file?
Also I'm also having trouble being able to read from the text file. First of all I can't figure out how to determine if a selected user is in the file or not. Form there, if the user is listed in the file, how can access the rest of the line, like only get the allowedTime of that user, or the remaining time?
I tried a couple of ways, but i just can't get it to do how I'm imaging it, if that makes sense.
here's the code so far:
Public Sub saveUserSetting(ByVal time As Integer)
Dim hash As HashSet(Of String) = New HashSet(Of String)(File.ReadAllLines("Settings.txt"))
Using w As StreamWriter = File.AppendText("Settings.txt")
If Not hash.Contains(selectedUserName.ToString()) Then
w.Write(selectedUserName + "; ")
w.Write(CStr(time) + "; ")
w.WriteLine(DateTime.Now.ToLongDateString() + "; ")
Else
w.Write(CStr(time) + "; ")
w.WriteLine(DateTime.Now.ToLongDateString() + "; ")
End If
End Using
End Sub
Public Sub readUserSettings()
Dim currentUser As String = GetUserName()
Dim r As List(Of String) = New List(Of String)(System.IO.File.ReadLines("Settings.txt"))
'For Each i = 0 to r.lenght - 1
'Next
'check to see if the current user is in the file
MessageBox.Show(r(0).ToString())
If r.Contains(selectedUserName) Then
MessageBox.Show(selectedUserName + " is in the file.")
'Dim allowedTime As Integer
Else
MessageBox.Show("the user is not in the file.")
End If
'if the name is in the file then
'get the allowed time and the date
'if the date is older than the current date return the allowed time
'if the date = the current date then check thhe remaning time and return that
'if the date is ahead of the current date return the reamining and display a messgae that the current date needs to be updated.
End Sub
edit: I just wanted to make sure if I'm doing the serialization right and the same for the deserialization.
this is what i got so far:
Friend userList As New List(Of Users)
Public Sub saveUserSetting()
Using fs As New System.IO.FileStream("Settings.xml", IO.FileMode.OpenOrCreate)
Dim bf As New BinaryFormatter
bf.Serialize(fs, userList)
End Using
End Sub
Public Sub readUserSettings()
Dim currentUser As String = GetUserName()
Dim useList As New List(Of Users)
Using fs As New System.IO.FileStream("Settings.xml", IO.FileMode.OpenOrCreate)
Dim bf As New BinaryFormatter
useList = bf.Deserialize(fs)
End Using
MessageBox.Show(useList(0).ToString)
End Sub
<Serializable>
Class Users
Public userName As String
Public Property allowedTime As Integer
Public Property lastLoggedInDate As String
Public Property remainingTime As Integer
Public Overrides Function ToString() As String
Return String.Format("{0} ({1}, {2}, {3})", userName, allowedTime, lastLoggedInDate, remainingTime)
End Function
End Class
edit 2:
I'm not too familiar with try/catch but would this work instead?
Public Sub readUserSettings()
If System.IO.File.Exists("Settings") Then
Using fs As New System.IO.FileStream("Settings", FileMode.Open, FileAccess.Read)
Dim bf As New BinaryFormatter
userList = bf.Deserialize(fs)
End Using
Else
MessageBox.Show("The setting file doesn't exists.")
End If
End Sub
You have a few typos and such in your code, but it is pretty close for your first try:
Friend userList As New List(Of Users)
Public Sub saveUserSetting()
' NOTE: Using the BINARY formatter will write a binary file, not XML
Using fs As New System.IO.FileStream("Settings.bin", IO.FileMode.OpenOrCreate)
Dim bf As New BinaryFormatter
bf.Serialize(fs, userList)
End Using
End Sub
Public Sub readUserSettings()
' this doesnt seem needed:
Dim currentUser As String = GetUserName()
' do not want the following line - it will create a NEW
' useRlist which exists only in this procedure
' you probably want to deserialize to the useRlist
' declared at the module/class level
' Dim useList As New List(Of Users)
' a) Check if the filename exists and just exit with an empty
' useRlist if not (like for the first time run).
' b) filemode wass wrong - never create here, just read
Using fs As New System.IO.FileStream("Settings.bin",
FileMode.Open, FileAccess.Read)
Dim bf As New BinaryFormatter
' user list is declared above as useRList, no useList
useList = bf.Deserialize(fs)
End Using
' Console.WriteLine is much better for this
MessageBox.Show(useList(0).ToString)
End Sub
<Serializable>
Class Users
' I would make this a property also
Public userName As String
Public Property allowedTime As Integer
Public Property lastLoggedInDate As String
Public Property remainingTime As Integer
Public Overrides Function ToString() As String
Return String.Format("{0} ({1}, {2}, {3})", userName, allowedTime, lastLoggedInDate, remainingTime)
End Function
End Class
ToDo:
a) decide whether you want XML or binary saves. With XML, users can read/edit the file.
b) Use a file path created from Environment.GetFolder(); with a string literal it may end up in 'Program Files' when deployed, and you cannot write there.
c) when reading/loading the useRlist, use something like
FileStream(myUserFile, FileMode.Open, FileAccess.Read)
It wont exist the first time run, so check if it does and just leave the list empty. After that, you just need to open it for reading. For saving use something like:
FileStream(myUserFile, FileMode.OpenOrCreate, FileAccess.Write)
You want to create it and write to it. You might put the Load/Save code inside a Try/Catch so if there are file access issues you can trap and report them, and so you know the list did not get saved or read.
Using a serializer, the entire contents of the list - no matter how long - will get saved with those 3-4 lines of code, and the entire list read back in the 2-3 lines to load/read the file.
I don't have the answer to all your questions however I've been also working on a timer application and just recently started using text file to read and write information. The method I'm using has proven itself fairly easy to use and not very confusing. Here is an extract of my code:
Dim startup As String = "C:\Users\DigiParent\Desktop\Project data\Digitimeinfo.txt"
Dim reader As New System.IO.StreamReader(startup, Encoding.Default)
Dim data As String = reader.ReadToEnd
Dim aryTextFile(6) As String
aryTextFile = data.Split(",")
This will read everything in the text file and in sort separate everything in between the , and store them individual in the array. To put the code back in one line use
Dim LineOfText As String
LineOfText = String.Join(",", aryTextFile)
so you could write someting like this to write your info to a text file:
Dim startup As String = "C:\Users\DigiParent\Desktop\Project data\Digitimeinfo.txt"
Dim objWriter As New System.IO.StreamWriter(startup, False)
Dim aryTextFile(2) As String
aryTextFile(0) = pasword
aryTextFile(1) = user
aryTextFile(2) = remainingtime
LineOfText = String.Join(",", aryTextFile)
objWriter.WriteLine(LineOfText)
objWriter.Close()
and to read it you could use steam reader.
I want to read Stream that i get from XtrapivotGrid of DevExpress. I can save it in the computer but what i want is to save it in one of my table in my dataset called dataset1.
For now i have that code who permit to save it the directory Temp:.
Using FS As New IO.FileStream("D:\Temp\qqc.layout", IO.FileMode.Create)
PivotGridControl1.SaveLayoutToStream(FS)
End Using
Dim read As New System.IO.FileStream("D:\Temp\qqc.layout", IO.FileMode.Open, IO.FileAccess.Read)
DataSet1.LayoutMainRapport.ReadXml(read)
DataSet1.AcceptChanges()
read.Close()
The table LayoutMainRapport have 3 columns:
ID(Int)
Name(nvarchar(50))
Content(xml).
The output from the stream is xml.
thanks in advance!
I believe you should convert your saved layout into string and then save this string to database (and of course you can load this layout back from the database string value):
Private Function SaveLayoutToString(ByVal dxControl As DevExpressControl) As String
Using ms As MemoryStream = New MemoryStream()
dxControl.SaveLayoutToStream(ms)
Return Convert.ToBase64String(ms.ToArray())
End Using
End Function
Private Sub RestoreLayoutFromString(ByVal dxControl As DevExpressControl, ByVal layout As String)
If String.IsNullOrEmpty(layout) Then
Return
End If
Using ms As MemoryStream = New MemoryStream(Convert.FromBase64String(layout))
dxControl.RestoreLayoutFromStream(ms)
End Using
End Sub
Here DevExpressControl dxControl is the DevExpress control which supports saving and loading layout (XtraPivotGrid, XtraGrid, XtraLayoutControl etc.)
I simply had to save a name for the xml and after save it into my dataset.
Dim saveDialog As SaveLayout = New SaveLayout
If saveDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim read As New IO.MemoryStream
PivotGridControl1.SaveLayoutToStream(read)
read.Position = 0
Dim lecteur As New IO.StreamReader(read)
Dim ligne As DataRow = DataSet1.LayoutMainRapport.NewRow()
ligne("Nom") = saveDialog.txtNom.Text
ligne("Contenu") = lecteur.ReadToEnd()
DataSet1.LayoutMainRapport.Rows.Add(ligne)
LayoutMainRapportTableAdapter.Update(DataSet1)
End If