I have a problem to print data to Word document template in 2013 , Actually i can able to print data in word 2010(Using XSD file) using vb.net , but 2013 doesn't accept xmlnodes(i know they remove xml nodes in 2013).How can i print the data in word2013 .
My scenario is :
I create template with different font styles and Header colors with three tables .
I need to dynamically add the rows based on my data ( in all my tables ).
Please guide how can i move....
This is not quite an answer for xsd files. But by request i put this forward.
Opening the docx as a memory stream and in this example I have a table with a caption.
That is in the word document there is a table and when you select it and right click->properties->Alternative Text -> title.
This title is the thing that I search for in the word document to know where to add my stuff. There are probably much better ways of doing this. But this makes the document editable for administrators and as long as they dont delete the table they can edit it as they see fit.
dim mem As MemoryStream
dim doc = WordprocessingDocument.Open(mem, true)
Dim tableProperties = doc.MainDocumentPart.Document.Body.Descendants(Of TableProperties)().Where(Function(tp) tp.TableCaption IsNot Nothing)
For Each tProp As TableProperties In tableProperties
If tProp.TableCaption.Val.ToString() = "DatatableTitle" Then
Dim tbl = DirectCast(tProp.Parent, Table)
InsertTableRows(tbl, myListOfThings)
End If
Next
Private Function CreateTableCellText(myText As String) As TableCell
Dim run = New Run()
Dim runProperties = New RunProperties()
runProperties.Append(New RunFonts() With { .Ascii = "Times New Roman" })
runProperties.Append(New FontSize() With { .Val = "16" })
run.PrependChild(runProperties)
run.Append(New Text(myText))
Dim p = New Paragraph()
p.Append(run)
Dim td = New TableCell()
td.Append(p)
Return td
End Function
Private Sub InsertTableRows(tbl As Table, patients As List(Of MyTableList))
'var refRow = tbl.Elements<TableRow>().ElementAt(1); // the first is the header.
tbl.Elements(Of TableRow)().ElementAt(1).Remove()
For Each patient As MyTableList In patients
Dim tr = New TableRow()
tr.Append(CreateTableCellText(patient.DepartmentName))
tr.Append(CreateTableCellText(patient.PatientLastName))
tbl.Append(tr)
Next
End Sub
End Class
Public Class MyTableList
Public Property DepartmentName() As String
Get
Return m_DepartmentName
End Get
Set
m_DepartmentName = Value
End Set
End Property
Private m_DepartmentName As String
Public Property PatientLastName() As String
Get
Return m_PatientLastName
End Get
Set
m_PatientLastName = Value
End Set
End Property
Private m_PatientLastName As String
End Class
And adding checkboxes and such is no problem, just create them in word, open the word document in a texteditor and copy the xml from the document and add it as new paragraph and then use firstChild.InnerXml and copy the xml into the text. and then append it
Related
This is a follow on question to a post I made. Append one file into another file
I need to search the master document for entities "&CH1.sgm" to "&CH33.sgm",
mark where they are in the master document and replace the entity call with the matching file "Chapter1.sgm" found in "fnFiles". I can change the file names and entities to anything if that will help.
My code copies the text of a file and appends it to the bottom of the master_document.sgm. But now I need it to be more intelligent. Search the Master document for entity markers, then replace that entity marker with that file contents match. The file number and entity number match up. e.g.(&CH1; and Bld1_Ch1.sgm)
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
Dim searchDir As String = txtSGMFile.Text 'Input field from form
Dim masterFile = "Bld1_Master_Document.sgm"
Dim existingFileMaster = Path.Combine(searchDir, masterFile)
'Read all lines of the Master Document
Dim strMasterDoc = File.ReadAllText(existingFileMaster) '// add each line as String Array.
'?search strMasterDoc for entities &Ch1.sgm
'?replace entity name "&Ch1.sgm" with content of file "Bld1_Ch1.sgm" this content if found below
'? do I use a book mark? Replace function?
'Get all the sgm files in the directory specified
Dim fndFiles = Directory.GetFiles(searchDir, "*.sgm")
'Set up the regular expression you will make as the condition for the file
Dim rx = New Regex(".*_Ch\d\.sgm")
Dim ch1 = New Regex(".*_Ch[1]\.sgm")
'Use path.combine for concatenatin directory together
'Loop through each file found by the REGEX
For Each fileNo In fndFiles
If rx.IsMatch(fileNo) Then
If ch1.IsMatch(fileNo) Then
Dim result = Path.GetFileName(fileNo)
'Use path.combine for concatenatin directory together
Dim fileToCopy = Path.Combine(searchDir, result)
'This is the file we want to copy into MasterBuild but at specific location.
'match &ch1.sgm inside strMasterDoc
Dim fileContent = File.ReadAllText(fileToCopy)
'Search master file for entity match then append all content of fileContent
File.AppendAllText(existingFileMaster, fileContent)
MessageBox.Show("File Copied")
End If
End If
Next
Close()
End Sub
If I understand correctly (big if), you want to replace the the text of the abbreviated chapter name in the master file with the contents of the file it refers to at the spot where the abbreviation is found.
I made a class to handle the details.
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
'Add a FolderBrowseDialog to your form designer
FolderBrowserDialog1.ShowDialog()
Dim searchDir As String = FolderBrowserDialog1.SelectedPath
Dim existingFileMaster = Path.Combine(searchDir, "Bld1_Master_Document.sgm")
Dim lstFileChanges = CreateList(searchDir)
'The following method does NOT return an array of lines
Dim strMasterDoc = File.ReadAllText(existingFileMaster)
For Each fc In lstFileChanges
strMasterDoc = strMasterDoc.Replace(fc.OldString, fc.NewString)
Next
File.WriteAllText(existingFileMaster, strMasterDoc)
End Sub
Private Function CreateList(selectedPath As String) As List(Of FileChanges)
Dim lstFC As New List(Of FileChanges)
For i = 1 To lstFC.Count
Dim fc As New FileChanges
fc.OldString = $"&CH{i}.sgm"
fc.FileName = $"Chapter{i}.sgm"
fc.NewString = File.ReadAllText(Path.Combine(selectedPath, fc.FileName))
lstFC.Add(fc)
Next
Return lstFC
End Function
Public Class FileChanges
Public Property OldString As String '&CH1.sgm
Public Property FileName As String 'Chapter1.sgm
Public Property NewString As String 'Contents of Chapter1.sgm, the string to insert
End Class
Testing .Replace
Dim s As String = "The quick brown fox jumped over the lazy dogs."
s = s.Replace("fox", "foxes")
MessageBox.Show(s)
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 am currently working on a Library Inventory System. I wanted it to be able to add, issue, search and delete book records. The records are stored in a text file which looks like this:
(ID), (Name Of Book); (Author); (Price) ; (Book Donor) ; (Language)
E.g.
123 , Journey to the center of the earth ; Jules Verne ; 50 ; Jack ; English
...
This program also works with a datagridview to update to/from the text file, so far my add and issue functions are working but i am having trouble with search and delete.
To search, the user must either enter the ID of the book in a textbox or the language of the book (separate textbox) and it must show the search results in the datagridview.
This is the my attempt for the search function:
Dim line As String
Dim fields(7) As String
Dim found As Boolean = False
Dim inputStream As StreamReader
inputStream = File.OpenText("AddBookScreen.txt")
line = inputStream.ReadLine()
While (line <> Nothing) And found = False
fields = Split(line, ",")
If Trim(fields(0)) = SBidTextbox.Text Then
SBdatagridview.Rows.Add(Trim(fields(1)), Trim(fields(2)), Trim(fields(3)), Trim(fields(4)), Trim(fields(5)), Trim(fields(6)))
found = True
Else
line = inputStream.ReadLine()
End If
End While
If Not found Then
MessageBox.Show(SBidTextbox.Text & " not found")
End If
inputStream.Close()
End Sub
The delete function should be able to find the specific book by id and then delete that record from the text file.
This is my attempt for the delete function:
Dim lines() As String
Dim outputlines As New List(Of String)
Dim searchString As String = DBidTextbox.Text
lines = IO.File.ReadAllLines("AddBookScreen.txt")
For Each line As String In lines
If line.Contains(searchString) = False Then
outputlines.Add(line)
End If
Next
The search and delete methods are meant to search for a specific book in the text file by either the ID of the book or the language and display the results in the datagridview, the delete method is to search for a specific record through ID and delete that record.
Could someone please guide me through these problems, your help would be much appreciated.
If you can change your text file format slightly (Only use one kind of delimiter - either comma or semi-colon), then you can use the Microsoft Text Driver. This allows you to treat the text file like a database table, and you can use SQL statements to SELECT, DELETE, or UPDATE. Below is an example:
Public Sub Delete(ByVal ID As String)
Dim SQL As String = String.Format("DELETE FROM myfile.csv WHERE ID={0}", ID)
Dim conn_str As String = String.Format("Driver={{Microsoft Text Driver (*.txt; *.csv)}};Dbq={0};Extensions=asc,csv,tab,tsv,txt;", folder)
Dim conn As New OdbcConnection(conn_str)
conn.Open()
Dim cmd As New OdbcCommand(sqltxt, conn)
Dim reader As OdbcDataReader = cmd.ExecuteNonQuery()
...
End Sub
If this system has any publicly facing user input, I would definitely recommend using a Parameterized Query to prevent SQL injection attacks.
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've seen a couple of posts asking a similar question but I have not been able to duplicate the answers in my code successfully.
The following code adds items and their value member to a list box.
Public Shared Sub ListFiles(hTab As Hashtable)
Debug.Print("create file and key" & Now)
Dim Enumerator As IDictionaryEnumerator
Enumerator = hTab.GetEnumerator()
Dim MyKeys As ICollection
Dim Key As Object
MyKeys = hTab.Keys()
If (hTab.Count > 0) Then
For Each Key In MyKeys
Dim sfileName As String = hTab(Key)
Dim first As Integer = sfileName.IndexOf("_")
Dim last As Integer = sfileName.LastIndexOfAny("_")
Dim first2 = (first + 1)
Dim splitFile = sfileName.Substring(first2)
frmViewFiles.ListBox1.Items.Add(splitFile)
frmViewFiles.ListBox1.ValueMember = Key
frmViewFiles.ListBox1.SelectedValue = Key
Next
End If
End Sub
When I run my code to get the selected items value member
Dim file = ListBox1.ValueMember.ToString()
I can acess the first item I choose but subsequent selections dont change the value member to that of the selected item.
Please direct me.
Thank you for your answers. this is my new code:
Public Shared Sub runListFiles(CustomerId As String)
Dim cfp As New CloudFilesProvider(cloudId)
Dim containerObjectList As IEnumerable(Of ContainerObject) = cfp.ListObjects(container:="EstherTest", identity:=cloudId, prefix:=CustomerId & "_")
For Each file As ContainerObject In containerObjectList
Dim sFullFileName As String = file.Name
Dim first As Integer = sFullFileName.IndexOf("_")
Dim first2 = (first + 1)
Dim splitFile = sFullFileName.Substring(first2)
'frmViewFiles.ListBox1.Items.Add(splitFile)
'frmViewFiles.ListBox1.ValueMember = sFullFileName
Dim fb = New myFile
fb.FileName = splitFile
fb.FullPath = sFullFileName
frmViewFiles.ListBox1.Items.Add(fb)
frmViewFiles.ListBox1.DisplayMember = fb.FileName
frmViewFiles.ListBox1.ValueMember = fb.FullPath
This is my class:
Public Class myFile
Public Property FileName As String
Public Property FullPath As String
Public Sub New(f As String, b As String)
FileName = f
FullPath = b
End Sub
End Class
Please see my comment below and assist
ValueMember is supposed to indicate the property name of an object added to the Items collection: the property to use as the actual value for the items in the ListControl.
You are not adding objects to the control, so Key from the hashtable is meaningless as the ValueMember. Your post references a file variable in passing, so I will assume this revolves around showing the filename while wanting to get the full pathname when selected/clicked. WebForms/Winforms/WPF was not indicated, I am assuming WinForms:
Public Class myFile
Public Property FileName As String
Public Property FullPath As String
Public Property FileSize As Int64 ' just so there is something else
Public Sub New(f as String, p as String, s as Int64)
FileName = f
FullPath = b
FileSize = s
End Sub
End Class
Lets say we want to add some of these to a ListBox, for each item added we want FileName to display as the text, but want to get them back by FullPath:
Dim f As myFile
' assume these come from a fileinfo
For Each fi as FileInfo in DirectoryInfo.GetFiles(searchFor)
f = New myFile
f.FileName = fi.Name
f.FullPath = fi.FullPath
f.FileSize = fi.Length
' myFile accepts all the prop values in the constructor
' so creating a new one could also be written as:
' f = New myFile(fi.Name, fi.FullPath, fi.Length)
myListBox.Items.Add(f)
Next n
If the myFile objects were stored to a List(of myFile) rather than adding them to the control, we can bind the List as the DataSource and not have to iterate or copy:
mylistBox.DataSource = myFileList
Either way, Display- and ValueMember refer to the property names we wish to use:
myListBox.DisplayMember = "FileName" ' indicate property name of obj to SHOW
myListBox.ValueMember = "FullPath" ' prop name of object to return
When you select a listbox item, myListBox.SelectedValue would refer to the FullPath of the myFile object clicked on. The SelectedIndex would still refer to the index of the item in the list.
tl;dr
ValueMember and DisplayMember refers to the Property Names of Objects represented in the list.
Note:
I know this is many years later, but still relevant information.
It took me a while to parse what was said above, until I grokked it fully, so I thought it might help if I restated it slightly.
When you select a listbox item,
myListBox.SelectedValue is the contents of the field, myListBox.ValueMember. ValueMember contains the Field Name, SelectedValue contains the contents of the field.
myListBox.SelectedItem is the contents of the field myListBox.DisplayMember. DisplayMember contains the field name and SelectedItem contains the value of the field.
The SelectedIndex refers to the index of the item in the list. To see which item is selected, reference myListBox.SelectedIndex. You can, for example, change the selection to the last item in the list by using myListBox.SelectedIndex = myListBox.Items.Count - 1
If you want to display the values, then
Console.WriteLine("The value of {0} is {1}",myListBoxDisplayMember,myListBox.SelectedItem)
Console.WriteLine("The Value of {0} is {1}",myListBox.ValueMember,myListBox.SelectedValue)