Windows Forms - How to access ListView's SubItems by column name? - vb.net

I've tried this but it's giving me 'System.NullReferenceException':
For Each MyListViewItem As ListViewItem In MyListView.Items
MsgBox(MyListViewItem.SubItems("MyColumn").Text)
Next
These lines of codes work (weird!):
For Each MyListViewItem As ListViewItem In MyListView.Items
MsgBox(MyListViewItem.SubItems(0).Text)
Next
But I need to access them by column name.
I found that this code gives me blank subitem name
For Each MyListViewItem As ListViewItem In MyListView.Items
MsgBox(MyListViewItem.SubItems(0).Name)
Next
Note that I added the columns in design time. While items in run-time:
While Reader.Read
Dim SubItems(2) As String
SubItems(0) = Reader("ItemForMyColumn")
SubItems(1) = Reader("ItemForSomeOtherColumn")
MyListView.Items.Add(New ListViewItem(SubItems))
End While
Thanks in advance!

It is likly throwing the null reference exception when trying to access the Text property on the SubItems("MyColumn") part of your sample.
You could check to see if MyListViewItem.SubItems("MyColumn") is not null before trying to read the Text property from it.
It could also be (based on your edit) that the name you are using to look it up doesn't match that's in the SubItems list.
If you print the name that you are looking for by using the index, what do you see?
After Edits
I might be this wrong, but it looks like by using this constructor for the ListViewItem, it's only going to be getting the Text property set.
I suggest trying something like this in your init code for the ListViewItem
(Forgive me, my VB is really really rusty and I don't have VS open)
While Reader.Read
Dim listViewItem As New ListViewItem()
Dim subItem1 As New ListViewSubItem()
subItem.Text = Reader("ItemForMyColumn")
subItem1.Name = "MyColumn"
//Do this as many times as you need
listViewItem.SubItems.Add( subItem1 )
MyListView.Items.Add( listViewItem )
End While

I think the you can get any subitems by its name as below:
When add columns dynamically
ListView1.Column.Add(dr("attribute_name"),dr("attribute_label"),dr("attribute_width"))
Then when get any subitems
ListView1.SelectedItems.Item(0).SubItems(ListView1.Column("attribute_name").Index).Text

Related

How to check datagridview column already exists with same Header Text Before adding a new Column in VB.net

I am trying to add columns dynamically to data grid view using VB.net. But the issue is I need to check that the column name already exists. before adding it if exists I want it to be cancelled automatically. I am using another form to select the Job Nos. which will add as Datagridview Header Text when it saved. () below is the code I am using to add a column to my datagridview. Hope you understand the question. I found some nearby answers in C# unfortunately I am not able to convert those correctly as my C# coding knowledge is little weak.
Thank You!
Dim FRMP = FrmEReview.ReviewGrid.Columns
Dim NOHRS As New DataGridViewTextBoxColumn
FRMP.Add(NOHRS)
NOHRS.HeaderText = Me.Cmb_CName.Text & "-" & Me.Cmb_DName.Text
NOHRS.Width = 160
The obvious option - the one you should have been able to work out for yourself - is to simply loop through the columns and test the HeaderText of each one:
Dim headerText = $"{Cmb_CName.Text}-{Cmb_DName.Text}"
Dim headerTextFound = False
For Each column As DataGridViewColumn In FrmEReview.ReviewGrid.Columns
If column.HeaderText = headerText Then
headerTextFould = True
Exit For
End If
Next
If Not headerTextFound Then
'...
End If
This is basically the code equivalent of what you'd do manually, which is why you should have been able to do it for yourself, at least mostly.
The not-so-obvious solution for a beginner is to use LINQ. LINQ is basically a means to flatten loops like this, so it leads to far more succinct code:
Dim headerText = $"{Cmb_CName.Text}-{Cmb_DName.Text}"
If FrmEReview.ReviewGrid.
Columns.
Cast(Of DataGridViewColumn)().
All(Function(dgvc) dgvc.HeaderText <> headerText) Then
'...
End If

Using StringBuilder to Append Contents of a List Box to a Text File

I am trying to create a programme in visual studio where, once you press a button, the contents of a ListBox are added to a text file.
I am currently using a StringBuilder to do this as my professor has told me this is the easiest and quickest way -I am aware I can use StreamWriter as well.
Dim CreateReciept As New System.Text.StringBuilder
CreateReciet.Append(lstOrderForm.Text & vbCrLf)
System.IO.File.WriteAllText("order_receipt.txt", Text.ToString())
Process.Start("order_receipt.txt")
This is my code as of now; however, when I run it, it produces a blank form rather than the contents of the list box.
You are looking at the wrong thing. ListBox.Text will only provide the text of the currently selected item:
When the value of this property is set to a string value, the ListBox searches for the item within the ListBox that matches the specified text and selects the item. You can also use this property to determine which items are currently selected in the ListBox. If the SelectionMode property of the ListBox is set to SelectionMode.MultiExtended, this property returns the text of the first selected item. If the SelectionMode property of the ListBox is not set to SelectionMode.None, this property returns the text of the first selected item.
Instead loop through the ListBox.Items collection:
This property enables you to obtain a reference to the list of items that are currently stored in the ListBox. With this reference, you can add items, remove items, and obtain a count of the items in the collection. For more information about the tasks that can be performed with the item collection, see the ListBox.ObjectCollection class reference topics.
Lastly don't use Text.ToString, that won't work. Instead use your StringBuilder:
Dim sb As New StringBuilder
For Each item In lstOrderForm.Items
sb.Append(item.ToString() & vbCrLf)
Next
System.IO.File.WriteAllText("order_receipt.txt", sb.ToString())
Process.Start("order_receipt.txt")
The code produces the following output for me:
Try the following instead:
Dim CreateReciet As New System.Text.StringBuilder
CreateReciet.Append(lstOrderForm.Text & vbCrLf)
System.IO.File.WriteAllText("order_receipt.txt", CreateReciet.ToString())
Process.Start("order_receipt.txt")
As I said above though, your stringbuilder isn't doing anything useful, so you could just write:
System.IO.File.WriteAllText("order_receipt.txt", lstOrderForm.Text & vbCrLf)
Process.Start("order_receipt.txt")

Texboxes Values in specified order from tabcontrol VB

I have a vb project of an event ticket selling stuff, and at the end I need to save a text file for each purchase.
I have tabbed controls, and at the very end, all the data that needs to go in the text file (event and customer) are in one tab.
I have this code, that will read the text from each textbox, and for now for testing purposes it throws a message box with the value. It is working, the only thing is, that it displays the values in an odd order and I don't know how to have them read in the required order.
(also it wouldn't hurt, if I could add the labels before the textbox.text but I'm not that greedy :) )
For Each GenericControl In TabPurchaseTickets.Controls
If TypeOf GenericControl Is System.Windows.Forms.TextBox Then
Dim tb As TextBox = DirectCast(GenericControl, TextBox)
MsgBox(tb.Text)
End If
Next
You need to have something that helps you identify these textboxes and their values before writing them on a file.
Relying on the order of the textboxes on the tabcontrol will be a great mistake in future revision of your application. If you need to change that order older file will cause a 'versioning' problem.
You could define the Tag property at design time for each textbox with a value that helps you identify them and write your file with the tag value, a separator and the textbox value
Dim sb = new StringBuilder()
For Each GenericControl In TabPurchaseTickets.Controls.OfType(Of TextBox)
Dim tb As TextBox = DirectCast(GenericControl, TextBox)
sb.AppendFormat("{0};{1}", tb.Tag, tb.Text)
sb.AppendLine()
Next
And now write the StringBuilder.ToString to your textfile, you will end up with something like this
Name;John
Surname;McInroe
Sport;Tennis
....
In this way you could change the order of your textboxes as you like becase every value is associated to the Tag property and you could easily reload it.
Of course this is just an example and I suggest you to investigate the use of a proper database system instead of a simple file.
It is a really ugly solution, but it works. Unfortunately in this project this is plenty! :D
Thanks for the tag idea, it's nice to find out that there is another field where I can "store" text in a textbox.
anyway, here is the bodge code *note the msgbox is just for testing the output, this will be modified to save in a textfile later:
Dim labels(15) As String
Dim fields(15) As String
For Each GenericControl In TabPurchaseTickets.Controls.OfType(Of TextBox)()
Dim tb As TextBox = DirectCast(GenericControl, TextBox)
fields(tb.TabIndex) = tb.Text
labels(tb.TabIndex) = tb.Tag
Next
For i As Integer = 0 To 15
MsgBox(labels(i) & ": " & fields(i))
Next

How can I use value of a string to control another control in VB.net?

I have been playing around with some code, and I have made easily 50+ controls that all are labeled: PictureBox[XCoordinate]_[YCorrdinate] (Replacing the brackets and contents with the coordinates of them on a little grid I made.)
The problem with this is it is a real pain to use a control when doing loops to update all the picture boxes. I want to know how to do code like:
'This code assumes that the picture boxes are all initialized.
Dim XCoordiante As Integer = 5
Dim YCorrdinate As Integer = 2
PictureBox[XCoordinate]_[YCoordiante].Image = [Put Image Here]
I am going to put this within a loop. Is there a way that I can do this without manually typing it all and risking missing something within a case statement? And also, I would have to retype it for every different kind of change I want to make (ex: tag or error image).
Would a pointer somehow help? I don't really know how to do this, but it would be really helpful if possible.
When you create them, save them to a List:
Private pList As New List(Of PictureBox)
Dim pic As New PictureBox
With Pic
.Location = ...
' etc
End With
Me.Controls.Add(pic)
pList.Add(pic)
Assuming they are created in some sort of order:
For n As integer = 0 To pList.Count = 1
' add code to look at Plist(n).X and .Y to determine what to do (?)
Plist(n).Image = ...
Next n
If there is more info to capture, create a custom class of a PicBox and the other info, and make the list a List(Of myPicClass).

ComboBox DataBinding DisplayMember and LINQ queries

Update
I decided to iterate through the Data.DataTable and trimmed the values there.
Utilizing SirDemon's post, I have updated the code a little bit:
Sub test(ByVal path As String)
Dim oData As GSDataObject = GetDataObj(path)
EmptyComboBoxes()
Dim oDT As New Data.DataTable
Try
Dim t = From r In oData.GetTable(String.Format("SELECT * FROM {0}gsobj\paths ORDER BY keyid", AddBS(path))) Select r
If t.Count > 0 Then
oDT = t.CopyToDataTable
For Each dr As Data.DataRow In oDT.Rows
dr.Item("key_code") = dr.Item("key_code").ToString.Trim
dr.Item("descript") = dr.Item("descript").ToString.Trim
Next
dataPathComboBox.DataSource = oDT
dataPathComboBox.DisplayMember = "descript"
dataPathComboBox.ValueMember = "key_code"
dataPathComboBox.SelectedIndex = 0
dataPathComboBox.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
This works almost as I need it to, the data is originally from a foxpro table, so the strings it returns are <value> plus (<Field>.maxlength-<value>.length) of trailing whitespace characters. For example, a field with a 12 character length has a value of bob. When I query the database, I get "bob_________", where _ is a space.
I have tried a couple of different things to get rid of the whitespace such as:
dataPathComboBox.DisplayMember.Trim()
dataPathComboBox.DisplayMember = "descript".Trim.
But nothing has worked yet. Other than iterating through the Data.DataTable or creating a custom CopyToDataTable method, is there any way I can trim the values? Perhaps it can be done in-line with the LINQ query?
Here is the code I have so far, I have no problem querying the database and getting the information, but I cannot figure out how to display the proper text in the ComboBox list. I always get System.Data.DataRow :
Try
Dim t = From r In oData.GetTable("SELECT * FROM ../gsobj/paths ORDER BY keyid") _
Select r
dataPathComboBox.DataSource = t.ToList
dataPathComboBox.SelectedIndex = 0
'dataPathComboBox.DisplayMember = t.ToList.First.Item("descript")
dataPathComboBox.Enabled = True
Catch ex As Exception
Stop
End Try
I know that on the DisplayMember line the .First.Item() part is wrong, I just wanted to show what row I am trying to designate as the DisplayMember.
I'm pretty sure your code tries to set an entire DataRow to a property that is simply the name of the Field (in a strongly type class) or a Column (in a DataTable).
dataPathComboBox.DisplayMember = "descript"
Should work if the DataTable contains a retrieved column of that name.
Also, I'd suggest setting your SelectedIndex only AFTER you've done the DataBinding and you know you actually have items, otherwise SelectedIndex = 0 may throw an exception.
EDIT: Trimming the name of the bound column will trim just that, not the actual bound value string. You either have to go through all the items after they've been bound and do something like:
dataPathComboBox.Item[i].Text = dataPathComboBox.Item[i].Text.Trim()
For each one of the items. Not sure what ComboBox control you're using, so the item collection name might be something else.
Another solution is doing that for each item when it is bound if the ComboBox control exposes an onItemDataBound event of some kind.
There are plenty of other ways to do this, depending on what the control itself offers and what you choose to do.
DisplayMember is intended to indicate the name of the property holding the value to be displayed.
In your case, I'm not sure what the syntax will by since you seem to be using a DataSet, but that should be
... DisplayMember="Item['descript']" ...
in Xaml, unless you need to switch that at runtime in which case you can do it in code with
dataPathComboBox.DisplayMember = "Item['descript']"
Again, not 100% sure on the syntax. If you are using a strongly typed DataSet it's even easier since you should have a "descript" property on your row, but given hat your error indicates "System.DataRow" and not a custom type, I guess you are not.
Because I can't figure out the underlying type of the datasource you are using I suggest you to change commented string to
dataPathComboBox.DisplayMember = t.ElementType.GetProperties.GetValue(0).Name
and try to determine correct index (initially it is zero) in practice.