Make DataRepeater bound to List(Of Object) update? - vb.net

What is the correct way to bind a List(Of Object) to a DataRepeater? Can you provide example code for this?
I have been racking my brains on this and while I can get an already filled list to show in the repeater, subsequent changes to the list have no effect on the DataRepeater.
Ultimately I hope to use this to bind to a dictionary, if that is possible, but I cannot even get the basics working here.
The data repeater is added on the form design surface, with 3 labels and a progress bar in the ItemTemplate. The code I have attempted (where DutData is the DataRepeater) to setup the list and repeater is then:
Public Class BurnIn
Public Shared currentDuts As New Dictionary(Of UInteger, DeviceUnderTest) ' Collection of all current DUTs.
Dim bs As New BindingSource
Dim testTemp As Boolean = False
Dim testList As New List(Of DeviceUnderTest)
Private Sub BurnIn_Load() Handles Me.Load
'...
' Add two items to the dictionary and populate them
currentDuts.Add(0, New DeviceUnderTest(Me.user, 0))
currentDuts.Item(0).RackBay = "012345678901"
currentDuts.Item(0).AssemblySerial = "123456789"
currentDuts.Item(0).SetProgram(1, "Program1")
currentDuts.Add(currentDuts.Count, New DeviceUnderTest(Me.user, 1))
currentDuts.Item(1).RackBay = "109876543210"
currentDuts.Item(1).AssemblySerial = "1319A5126"
currentDuts.Item(1).SetProgram(1, "Program1")
' Copy the items to the test list.
testList.Add(currentDuts.Item(0))
testList.Add(currentDuts.Item(1))
testTemp = True
' Setup the binding source, data source and data bindings.
bs.DataSource = testList
LocationLabel.DataBindings.Add("Text", bs, "RackBay")
DutLabel.DataBindings.Add("Text", bs, "AssemblySerial")
ProgramLabel.DataBindings.Add("Text", bs, "Program")
DutProgress.DataBindings.Add("Value", bs, "Progress")
DutData.DataSource = testList
'...
Me.Show()
End Sub
Then to test adding or removing list items:
Private Sub Button1_Click() Handles Button1.Click
If testTemp = False Then
' Add an item to the dictionary and populate it.
currentDuts.Add(currentDuts.Count, New DeviceUnderTest(Me.user, 1))
currentDuts.Item(1).RackBay = "109876543210"
currentDuts.Item(1).AssemblySerial = "1319A5126"
currentDuts.Item(1).SetProgram(1, "Program1")
' Copy the item to the test list.
testList.Add(currentDuts.Item(1))
testTemp = True
Else
' Remove the item from the dictionary and the list.
currentDuts.Remove(1)
testList.Remove(testList.Item(1))
testTemp = False
End If
End Sub
End Class

First thing is to replace your List with a BindingList
Dim testList As New BindingList(Of DeviceUnderTest)

Related

How would you structure data with different datatypes in VB.NET

Right now I have many locations with this structure. At the moment I have: name as string and x,y,z positions as single. So it's a mix of data types and I might want to add both more data in the future and also other data types. I must be able to easily extract any part of this data.
Example of how I'll work with this data is: When I choose South Wales from a combobox then I want to get its properties, x,y,z populated in a textbox. So they need to be "linked". If I choose London then it'll have its x,y,z properties etc.
My initial idea is just to dim every single data such as in the first example below. This should be the easiest way with 100% control of what's what, and I could easily extract any single data but at the same time might get tedious I assume, or am I wrong? Is it a good way to approach this?
Dim SW_FP As String = "South Wales"
Dim SW_FP_X As Single = "489,1154"
Dim SW_FP_Y As Single = "-8836,795"
Dim SW_FP_Z As Single = "109,6124"
The next example below is something i just googled up. Is this a good method?
Dim dt As DataTable = New DataTable
dt.Columns.Add("South Wales", GetType(String))
dt.Columns.Add("489,1154", GetType(Single))
dt.Columns.Add("-8836,795", GetType(Single))
dt.Columns.Add("109,6124", GetType(Single))
OR should I use something else? Arrays, Objects with properties... and this is where my ideas end. Are there other methods? XML?
I want to do it in a smart way from start instead of risking to rewrite/recreate everything in the future. So my main question is: Which method would you suggest to be the smartest to choose? and also if you could provide a super tiny code example.
You mentioned that when you choose an item you want to get it's properties. This shows that you are looking for objects. If not using a database one example could be to make Location objects and have a List of these to be added or removed from. Then you have a lot of different ways to get the data back from the List. For example:
Class:
Public Class Location
Public Property Name As String
Public Property X As Single
Public Property Y As Single
Public Property Z As Single
End Class
List:
Dim locations As New List(Of Location)
Dim location As New Location With {
.Name = "South Wales",
.X = 1.1,
.Y = 1.2,
.Z = 1.3
}
locations.Add(location)
LINQ to get result:
Dim result = locations.SingleOrDefault(Function(i) i.Name = "South Wales")
This is just an example for use within your program, hope it helps.
Disclaimer: Untested code. It's more to guide you than copy-paste into your project.
First, create a Class that will represent the structured data:
Public Class Location
Public Property Name As String
Public Property PositionX As Single
Public Property PositionY As Single
Public Property PositionZ As Single
Public Sub New()
Me.New (String.Empty, 0, 0, 0)
End Sub
Public Sub New(name As String, x As Single, y As Single, z As Single)
Me.Name = name
Me.PositionX = x
Me.PositionY = y
Me.PositionZ = z
End Sub
Now, you can create a List(Of Location) and use that List to bind to a ComboBox, like this:
Dim list As New List(Of Location) = someOtherClass.ReadLocations ' Returns a List(Of Location) from your database, or file, or whatever.
cboLocations.DataSource = list
cboLocations.DisplayMember = "Name" ' The name of the Location class' Property to display.
cboLocations.ValueMember = "Name" ' Use the same Name Property since you have no ID.
You can also forego the list variable declaration like the following, but I wanted to show the declaration of list above:
cboLocations.DataSource = someOtherClass.ReadLocations
Function someOtherClass.ReadLocations() may populate the List(Of Locations) in a way similar to this. Note I'm not including data access code; this is just an example to show how to add Location objects to the List(Of Location):
Dim list As List(Of Location)
' Some loop construct
For each foo in Bar
Dim item As New Location(foo.Name, foo.X, foo.Y, foo.Z)
list.Add(item)
' End loop
Return list
The "magic" happens when you select an option from the ComboBox. I forget the ComboBox event offhand, so that's homework for you :-) You take the selected Object of the ComboBox and cast it back to the native type, in this case Location:
Dim item As Location = DirectCast(cboLocations.SelectedItem, Location)
txtName.Text = item.Name
txtPosX.Text = item.PositionX.ToString
txtPosY.Text = item.PositionY.ToString
txtPosZ.Text = item.PositionZ.ToString
Here is one way, using a DataTable as you mentioned. This is a stand alone example project just to show code used.
This example loads data from file is found and saves data on exit.
Form1 Image
' Stand alone example
' needs DataGridView1, Label1 and
' ComboBox1 on the Designer
' copy/replace this code with default
Option Strict On
Option Explicit On
Public Class Form1
Dim dt As New DataTable("Freddy")
Dim bs As New BindingSource
'edit path/filename to use as test data path
Dim filepath As String = "C:\Users\lesha\Desktop\TestData.xml"
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
dt.WriteXml(filepath)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
With dt
dt.Columns.Add("Country", GetType(String))
dt.Columns.Add("x", GetType(String))
dt.Columns.Add("y", GetType(String))
dt.Columns.Add("z", GetType(String))
' add extra column to hold concatenated
' location (could be a hidden column)
dt.Columns.Add("CombLoc", GetType(String), "'x = ' + x + ' y = ' + y + ' z = ' + z")
If IO.File.Exists(filepath) Then
' saved file found so load it
dt.ReadXml(filepath)
Else
' no saved file so make one test row
.Rows.Add("South Wales", 489.1154, -8836.795, 109.6124)
End If
End With
bs.DataSource = dt
DataGridView1.DataSource = bs
' set any properties for DataGridView1
With DataGridView1
' to hide Combined Location column
.Columns("CombLoc").Visible = False
' dontwant row headers
.RowHeadersVisible = False
End With
set up ComboBox
With ComboBox1
.DataSource = bs
' displayed item
.DisplayMember = "Country"
' returned item
.ValueMember = "CombLoc"
If .Items.Count > 0 Then .SelectedIndex = 0
End With
' default Label text
Label1.Text = "No items found"
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
no items in list so exit sub
If ComboBox1.SelectedIndex < 0 Then Exit Sub
send returneditem to Label
Label1.Text = ComboBox1.SelectedValue.ToString
End Sub
End Class

Pasting new records to a Bound DataGridView

Apologies if this has already been asked. If so, I am unable to find a simple solution. I am trying to allow a user to copy/paste multiple records in a DataGridView (the in memory copy of the data, to be saved later when the user clicks the save button) and cannot find anything that works. It probably is because there is something I do not understand about all of this.
I set up a standard edit form with Visual Studio's drag/table into a form, so it's using a BindingSource control and all the other controls that come with doing that. It works just fine when manually entering something in the new row one by one, so it seems to be set up correctly, but when it comes to adding a record (or multiples) using code, nothing seems to work.
I tried a few things as outline in the code below. Could someone please at least steer me in the right direction? It cannot be that difficult to paste multiple records.
I run this when the user presses Control-V (the clipboard correctly holds the delimited strings):
Private Sub PasteClipboard()
If Clipboard.ContainsText Then
Dim sLines() As String = Clipboard.GetText.Split(vbCrLf)
For Each sLine As String In sLines
Dim Items() As String = sLine.Split(vbTab)
Dim drv As DataRowView = AdjustmentsBindingSource.AddNew()
drv.Item(1) = Items(0)
drv.Item(2) = Items(1)
drv.Item(3) = Items(2)
drv.Item(4) = Items(3)
'Error on next line : Cannot add external objects to this list.
AdjustmentsBindingSource.Add(drv)
Next
End If
End Sub
EDIT
(the bindingsource is bound to a dataadapter, which is bound to a table in an mdb file, if that helps understand)
I adjusted the inner part of the code to this:
If (RowHasData(Items)) Then
Dim drv As DataRowView = AdjustmentsBindingSource.AddNew()
drv.Item("FontName") = Items(0)
drv.Item("FontSize") = Items(1)
drv.Item("LetterCombo") = Items(2)
drv.Item("Adjustment") = Items(3)
drv.Item("HorV") = Items(4)
End If
It kinda works, but it also adds a blank row before the 2 new rows. Not sure where that is coming from, as I have even included your RowHasData() routine...
I would think that “attemp3” SHOULD work, however, it is unclear “what” the AdjustmentsBindingSource’s DataSource is. Is it a List<T> or DataTable?
If I set the BinngSource.DataSource to a DataTable, then attempt 3 appears to work. Below is an example that worked.
Private Sub PasteClipboard2()
If Clipboard.ContainsText Then
Dim sLines() As String = Clipboard.GetText.Split(vbCrLf)
For Each sLine As String In sLines
Dim Items() As String = sLine.Split(vbTab)
If (RowHasData(Items)) Then
Dim drv As DataRowView = AdjustmentsBindingSource.AddNew()
drv.Item("FontName") = Items(0)
drv.Item("FontSize") = Items(1)
drv.Item("LetterCombo") = Items(2)
drv.Item("Adjustment") = Items(3)
drv.Item("HorV") = Items(4)
End If
Next
End If
End Sub
This appears to work in my tests. I added a small function (RowHasData) to avoid malformed strings causing problems. It simply checks the size (at least 5 items) and also checks to make sure a row actually has “some” data. If a row is just empty strings, then it is ignored.
Private Function RowHasData(items As String())
If (items.Count >= 5) Then
For Each item In items
If (item <> "") Then Return True
Next
End If
Return False
End Function
I am guessing it would be just as easy to add the new rows “directly” to the BindingSource’s DataSource. In the example below, the code is adding the row “directly” to the DataTable that is used as a DataSource to the BindingSource. I am confident you could do the same thing with a List<T> by simply adding a new object to the list. Below is a complete example using a BindingSource and a DataTable. This simply adds the rows to the bottom of the table.
Dim gridTable1 As DataTable
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PasteClipboard()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
gridTable1 = GetTable()
FillTable(gridTable1)
AdjustmentsBindingSource.DataSource = gridTable1
AdjustmentsDataGridView.DataSource = AdjustmentsBindingSource
End Sub
Private Function GetTable() As DataTable
Dim dt = New DataTable()
dt.Columns.Add("FontName", GetType(String))
dt.Columns.Add("FontSize", GetType(String))
dt.Columns.Add("LetterCombo", GetType(String))
dt.Columns.Add("Adjustment", GetType(String))
dt.Columns.Add("HorV", GetType(String))
Return dt
End Function
Private Sub FillTable(dt As DataTable)
For index = 1 To 10
dt.Rows.Add("Name_" + index.ToString(), "Size_" + index.ToString(), "Combo_" + index.ToString(), "Adjust_" + index.ToString(), "HorV_" + index.ToString())
Next
End Sub
Private Sub PasteClipboard()
If Clipboard.ContainsText Then
Dim sLines() As String = Clipboard.GetText.Split(vbCrLf)
Try
Dim dataRow As DataRow
For Each sLine As String In sLines
Dim Items() As String = sLine.Split(vbTab)
If (RowHasData(Items)) Then
dataRow = gridTable1.NewRow()
dataRow("FontName") = Items(0)
dataRow("FontSize") = Items(1)
dataRow("LetterCombo") = Items(2)
dataRow("Adjustment") = Items(3)
dataRow("HorV") = Items(4)
gridTable1.Rows.Add(dataRow)
End If
Next
Catch ex As Exception
MessageBox.Show("Error: " + ex.Message)
End Try
End If
End Sub
Private Function RowHasData(items As String())
If (items.Count >= 5) Then
For Each item In items
If (item <> "") Then Return True
Next
End If
Return False
End Function
Hope the code helps…
Last but important, I am only guessing that you may have not “TESTED” the different ways users can “SELECT” data and “how” other applications “copy” that selected data. My previous tests using the WIN-OS “Clipboard” can sometimes give unexpected results. Example, if the user selects multiple items using the ”Ctrl” key to “ADD” to the selection, extra rows appeared in the Clipboard if the selection was not contiguous. My important point is that using the OS clipboard is quirky IMHO. I recommend LOTS of testing on the “different” ways the user can select the data. If this is not an issue then the code above should work.

Can I create a property of a property?

So I recently grasped the concept of using classes in my Visual Basic programming, and I found it tremendously helpful. In my current project, I have several groups boxes of check boxes (each check box denotes a "Behavior") and in each group box, there is always one check box that has a textbox control instead of a label (to allow the user to specify an "Other" behavior). It is that user-generated label that is giving me trouble...
I created a class called "Behaviors" that basically does the following:
getChecked > This method gets each checked checkbox and adds it to
the BehaviorCollection for a given Form.
behaviorCollection > represents the collection of checked
checkboxes.
getOtherChecked > does the same as "getChecked" except with the
"Other Behavior" checkboxes.
otherBehaviorCollection > represents the collection of checked
"Other" checkboxes.
The issue is that for each checked "Other Behaviors" checkbox, I need to store the value of its corresponding textbox. I would like to set my getOtherChecked() method to do this, so that in the end, I would be able to something like this...
Dim myBoxes as new Behaviors
Dim cBox as Checkbox
Dim cBoxLabel as String
myBoxes.getOtherChecked(myUserForm) 'This would get each checked "Other Behaviors" checkbox object, and also somehow add another property to it called "LinkedTextboxLabel" that would be assigned the value of the corresponding textbox.
cBox = myBoxes.otherBehaviorCollection.item(0) 'Assign a checkbox from my "Other Behaviors" collection to a variable.
cBoxLabel = cBox.LinkedTextboxLabel 'Assign the user-inputted value of the linked textbox to a variable.
So basically how could/should I add a custom-property to a collection item or checkbox?
I thought about just adding the names of the controls to a temporary DataTable or SQL table, so that each row would have the name of a checkbox in one column and its corresponding textbox value in the next, but I am hoping there is a more commonly used and accepted method.
Thank you in advance!
You could add a property for the text associated with the "Other Behaviors" checkbox.
EDIT: You might be trying to generalize your data too far, because the "Other behaviors" is a special case and deserves separate consideration.
If you have a look at what the following code (in a new Windows Forms project) creates, it might give you ideas:
Public Class Form1
''' <summary>
''' A behaviour domain and its characteristics, with one user-defined entry.
''' </summary>
''' <remarks></remarks>
Public Class BehavioursSectionDescriptor
Property BehaviourTypeName As String
Property BehaviourNames As List(Of String)
Property CustomBehaviours As String
End Class
''' <summary>
''' Return a GroupBox containing CheckBoxes and one Checkbox with a TextBox adjacent to it.
''' </summary>
''' <param name="behaviourSet"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function GetBehaviourGroupPanel(behaviourSet As BehavioursSectionDescriptor) As GroupBox
Dim gb As New GroupBox
gb.Text = behaviourSet.BehaviourTypeName
Dim fixedBehaviourNames As List(Of String) = behaviourSet.BehaviourNames
Dim customBehavioursValue As String = behaviourSet.CustomBehaviours
Dim cbVertSeparation As Integer = 4
Dim gbPadding As Integer = 20
Dim cb As New CheckBox
Dim yLoc As Integer = gbPadding
For i = 0 To fixedBehaviourNames.Count - 1
cb = New CheckBox
cb.Location = New Point(gbPadding, yLoc)
cb.Text = fixedBehaviourNames(i)
' you can use the .Tag Object of a Control to store information
cb.Tag = behaviourSet.BehaviourTypeName & "-Cb-" & i.ToString()
gb.Controls.Add(cb)
yLoc += cb.Height + cbVertSeparation
Next
cb = New CheckBox
cb.Text = ""
cb.Location = New Point(gbPadding, yLoc)
cb.Tag = behaviourSet.BehaviourTypeName & "-Custom behaviours"
gb.Controls.Add(cb)
Dim tb As New TextBox
tb.Location = New Point(gbPadding + 18, yLoc)
tb.Width = 100
tb.Text = customBehavioursValue
gb.Controls.Add(tb)
' make sure the textbox appears in front of the checkbox's label area
tb.BringToFront()
gb.Size = New Size(160, yLoc + gbPadding * 2)
Return gb
End Function
Private Function GetTestData() As List(Of BehavioursSectionDescriptor)
Dim bsds = New List(Of BehavioursSectionDescriptor)
bsds.Add(New BehavioursSectionDescriptor With {.BehaviourTypeName = "In water", _
.BehaviourNames = New List(Of String) From {"Floats", "Spins"}, _
.CustomBehaviours = "Paddles"})
bsds.Add(New BehavioursSectionDescriptor With {.BehaviourTypeName = "Under light", _
.BehaviourNames = New List(Of String) From {"Shines", "Glows", "Reflects"}, _
.CustomBehaviours = "Iridesces"})
bsds.Add(New BehavioursSectionDescriptor With {.BehaviourTypeName = "Near food", _
.BehaviourNames = New List(Of String) From {"Sniffs", "Looks"}, _
.CustomBehaviours = ""})
Return bsds
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim bsds As List(Of BehavioursSectionDescriptor) = GetTestData()
Dim gbs As New List(Of GroupBox)
Dim xLoc As Integer = 20
Dim yLoc As Integer = 20
' make some GroupBoxes to present the data input fields
For i = 0 To bsds.Count - 1
Dim gb = GetBehaviourGroupPanel(bsds(i))
gb.Location = New Point(xLoc, yLoc)
gb.Dock = DockStyle.None
yLoc += gb.Height + 30
Me.Controls.Add(gb)
Next
' size the form to fit the content
Me.Size = New Size(240, yLoc + 40)
End Sub
End Class
I know it doesn't answer the question of adding a property to a property, but could you create a class for the Other checkbox and override it's capabilities? Then you could add checkboxes and OtherCheckBoxes to your generic collection? for instance, (by no means complete, but you should get the idea)
EDIT: Changed code to show Shadows
Public Class OptionalCheckbox : Inherits CheckBox
Private mOptionalText As String
Public Shadows Property Text() As String
Get
Return mOptionalText
End Get
Set(value As String)
mOptionalText = value
MyBase.Text = value
End Set
End Property
End Class
For each item, if you were to retrieve .Text, you would either get your textbox value or your checkbox label (if it was a normal checkbox)
And how to utilize in other parts of your code. Again, this is just more of an example. You would still need to work with the textbox that is assigned to the OtherCheckBox to get it to write the text to that, as well as read from that into the .Text property of the Class.
Dim newCheckBoxCollection As New Collection
Dim cBox As New CheckBox
cBox.Text = "Standard Value Here"
'other properties of the checkbox can be modified here
newCheckBoxCollection.Add(cBox)
Dim cOBox As New OptionalCheckbox
cOBox.Text = "Optional Text Here"
'other properties of the checkbox can be modified here
newCheckBoxCollection.Add(cOBox)
For Each cb As CheckBox In newCheckBoxCollection
Me.FlowLayoutPanel1.Controls.Add(cb)
Next
If you are trying to just save the data into something like a DataTable or SQL table the code would be a bit of an overkill. I suggest you use a stream reader/writer and try checking the values that way as the code would be a lot more simple.

how do i initialize my arraylist

I have a function that adds items to my arraylist. my problem is that it only holds one item at a time since it is reinitializing the array lit every time I click my button. what is the syntax in VB to only initialize the array if it has not been created yet?
Dim itemSelectAs New ArrayList()
Dim Quantities As New ArrayList()
Dim itemQtyOrdered As Integer
Public Sub ShtickDataList_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.ListViewCommandEventArgs) Handles ShtickDataList.ItemCommand
If e.CommandName = "addToCart" Then
Dim itemQuantity As DropDownList = e.Item.FindControl("QuantityDropDown")
itemQtyOrdered = itemQuantity.SelectedValue
ItemSelect.Add(e.CommandArgument)
Quantities.Add(itemQtyOrdered)
Session("itemInCart") = ItemSelect
Session("quantities") = Quantities
viewInvoice()
End If
End Sub
Protected Sub viewInvoice()
Dim itemSelected As ArrayList = DirectCast(Session("itemInCart"), ArrayList)
Dim QuantityofItem As ArrayList = DirectCast(Session("quantities"), ArrayList)
Dim conn As SqlConnection
Dim comm As SqlCommand
Dim reader As SqlDataReader
Dim purimConnection2 As String = ConfigurationManager.ConnectionStrings("Purim").ConnectionString
conn = New SqlConnection(purimConnection2)
comm = New SqlCommand("SELECT ProductName FROM Products WHERE ProductID = #ProductID", conn)
Dim i As Integer
For i = 0 To ItemSelect.Count - 1
comm.Parameters.Add("#ProductID", Data.SqlDbType.Int)
comm.Parameters("#ProductID").Value = (ItemSelected.Count - 1)
'Next
Try
conn.Open()
reader = comm.ExecuteReader()
ViewCartlink.Text = "View Cart: (" & ItemSelected.Count & ")"
Finally
conn.Close()
End Try
End Sub
First you need to dimension your array list.
Dim array_list as ArrayList()
Then you can instantiate one
array_list = new ArrayList
Or you can combine it into one step:
Dim array_list = new ArrayList()
After that you can add and remove elements from your array list with
array_list.add(obj)
and remove with
array_list.remove(obj)
It looks like your problem is related to accessing the members of an arraylist. New items are always added to the end of an arraylist. To access them directly, you will need their index. If you know the index of the item you want to access use
array_list(i)
If you don't you will need to iterate over the array. To do this you have two options. You can use "for each" or you can use a normal for loop and use array_list.count as your upper bound.
You're recreating your two session values every time you call your button click menu. You need to pull them out of the Session variable and put them in local variables and put them back into the session variable.
Your button method should be:
Public Sub ShtickDataList_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.ListViewCommandEventArgs) Handles ShtickDataList.ItemCommand
if isNothing(itemSelect) Then itemSelect = New ArrayList()
if isNothing(itemQtyOrdered) Then itemQtyOrdered= New ArrayList()
If e.CommandName = "addToCart" Then
Dim itemQuantity As DropDownList = e.Item.FindControl("QuantityDropDown")
itemQtyOrdered = itemQuantity.SelectedValue
ItemSelect.Add(e.CommandArgument)
Quantities.Add(itemQtyOrdered)
Session("itemInCart") = ItemSelect
Session("quantities") = Quantities
viewInvoice()
End If
End Sub
And change your Global calls to:
Dim itemSelect As ArrayList() = Session("itemInCart")
Dim Quantities As New ArrayList() = Session("quantities")
Define your array outside the button click event. (Form level)
Then in the button click event try this:
If myArrayList Is Nothing then
'initializes the array list only if that hasn't happened yet
myArrayList = new ArrayList
End If
'adds the item to the existing list without causing it to reintialize
myArrayList.add(item)
That way it is initialized if it hasn't been, but not if it already has. If it is initialized at the form level ie... its declared as new already then you can just add to it.
Basically make sure that you aren't calling New for the arrayList in the button click event.
Editing for web form:
You should probably check where you initialize your arrayList. Like in the Page_Load:
If Not Page.IsPostBack Then
myArrayList = New ArrayList
End If
MSDN Postback

Referencing an Unbound DataGridView Without Specifically Naming It?

I am using 3 unbound DataGridView controls to display certain information. To load the information into those DGVs, I am pulling the information from an encrypted file, decrypting it, parsing the information, then trying to fill the DGVs with that information. The loading from the file is called by the menu item click. Here is what I have so far:
Private Sub miCLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles miCLoad.Click
Dim FilePath As String = "C:\FList\CList.clt"
Dim LoadFile As New SaveandLoad.SaveAndLoad
Dim FileRead As New Simple3Des("MyPassword")
Dim FileString As String = FileRead.ReadFile(FilePath)
With LoadFile
.WhichList = dgCourses
.FilePath = FilePath
.DecryptedString = FileRead.DecryptData(FileString)
.dgList = dgCourses
End With
Call LoadFile.LoadFile()
End Sub
Public Class SaveandLoad
Public Property WhichList As New DataGridView
Public Property FilePath As String
Public Property DecryptedString As String
Public Property EncryptedString As String
Public Property dgList As Control
Public Sub LoadFile()
Dim dgRow As DataGridViewRow
Dim dgCell As DataGridViewTextBoxCell
Dim Lines() As String = DecryptedString.Split(vbLf)
Dim LinesList As List(Of String) = Lines.ToList
LinesList.RemoveAt(Lines.Length - 1)
For Each Line As String In LinesList
Dim Fields() As String = Line.Split(",")
dgRow = New DataGridViewRow
For x = 0 To (WhichList.Columns.Count - 1) Step 1
dgCell = New DataGridViewTextBoxCell
dgCell.Value = Fields(x).ToString
dgRow.Cells.Add(dgCell)
Next
WhichList.Rows.Add(dgRow)
Next
Select Case WhichList.Name
Case "dgCourses"
frmFacultyList.dgCourses = WhichList
frmFacultyList.dgCourses.Refresh()
WhichList.Dispose()
Case "dgFList"
frmFacultyList.dgFList = WhichList
frmFacultyList.dgFList.Refresh()
WhichList.Dispose()
Case "dgSList"
frmFacultyList.dgSList = WhichList
frmFacultyList.dgSList.Refresh()
WhichList.Dispose()
End Select
MsgBox("List Successfully Loaded", vbOKOnly, "Load")
End Sub
I want to be able to reference (or fill) a DGV without using 'select case' or 'if-then' statements. This will be too inefficient once I start adding the many other DGVs, that will be added in the future. Therefore, the title is the main question. I am using VS Express 2010.
I don't know VB too much, however, I'll post my solution in C# (may be helpfull in some way....)
DataGridView myDGV;
foreach (var item in this.Controls)
{
if (item.GetType() == typeof(DataGridView))
{
if (((DataGridView)item).Name == WhichList.Name)
{
//Cannot assing to 'item' here, because it is a 'foreach iteration variable'
//However you can save the variable for later use.
myDGV = (DataGridView)item;
}
}
}
myDGV = WhichList;
// different approach
DataGridView myDGV = (DataGridView)this.Controls.Find(WhichList.Name, false).First();
myDGV = WhichList;
Here is what worked for me in VB.NET:
Dim FormControls As New frmFacultyList.ControlCollection(frmFacultyList)
For Each DGV As DataGridView In FormControls
If WhichList.Name = DGV.Name Then
DGV = WhichList
DGV.Refresh()
End If
Next
Make an instance of the control collection then search specifically for DGVs using For Each. Simple and efficient.