Creating label array in vb.net 2007
-
I have a table of 13 items that I need to display in sequence. The sequence can change from day to day based upon the previous days usage. One day the number 1 item may be 3/4" concrete lined rod, the next day that may be 5th and 5/8" SMPC may be the number one item. I pull the material from the table in the sequence order and then I want t fill in the label with the material name and the label tag property with the MaterialID which is a GUID. I found some code in a google search for creating a control array but I'm just not understanding it enough to get it to work in my project. The link for that is as follows: http://vbnet.codenewbie.com/articles/vbnet/1555/Mimicking\_VB6\_Control\_Arrays\_in\_VBNET-Page\_1.html My labels are named lblRods_0 to lblRods_12 and the code for loading them is:
Private Function LoadTabData() As Boolean 'We need to get the items for the frmLOL from the table Materials and load 'them into the text boxes in sequence. If user fills out anything we need to 'store it using the GUID stored in the tag property 'SELECT Materials.MaterialsID, Materials.Type, Materials.Sequence, Materials.Material 'FROM(Materials) 'ORDER BY Materials.Type, Materials.Sequence; Try gblConn = New OleDbConnection(JWIConnStr) Dim daMaterial As New OleDbDataAdapter Dim dsMaterial As New DataSet Dim mySelectQuery As String = "SELECT MaterialsID, Type, Sequence, Material " & \_ "FROM Materials " & \_ "ORDER BY Type, Sequence;" Dim myConnection As New OleDbConnection(JWIConnStr) Dim myCommand As New OleDbCommand(mySelectQuery, myConnection) myConnection.Open() daMaterial.SelectCommand = myCommand daMaterial.Fill(dsMaterial) If Not dsMaterial.Tables(0).Rows.Count > 0 Then MsgBox("Unable to locate MATERIALS. Please Cancel and retry later", MsgBoxStyle.OkOnly) Exit Function Else 'at least one record shows Dim recCount As Integer Dim dstbl As New DataTable daMaterial.Fill(dstbl) recCount = dsMaterial.Tables(0).Rows.Count Dim rowNdx As Integer Dim lblNdx As Integer rowNdx = 0 'Set to zero index value for the dsMaterial tbl lblNdx = 1 For Each Row In dstbl.Rows
-
I have a table of 13 items that I need to display in sequence. The sequence can change from day to day based upon the previous days usage. One day the number 1 item may be 3/4" concrete lined rod, the next day that may be 5th and 5/8" SMPC may be the number one item. I pull the material from the table in the sequence order and then I want t fill in the label with the material name and the label tag property with the MaterialID which is a GUID. I found some code in a google search for creating a control array but I'm just not understanding it enough to get it to work in my project. The link for that is as follows: http://vbnet.codenewbie.com/articles/vbnet/1555/Mimicking\_VB6\_Control\_Arrays\_in\_VBNET-Page\_1.html My labels are named lblRods_0 to lblRods_12 and the code for loading them is:
Private Function LoadTabData() As Boolean 'We need to get the items for the frmLOL from the table Materials and load 'them into the text boxes in sequence. If user fills out anything we need to 'store it using the GUID stored in the tag property 'SELECT Materials.MaterialsID, Materials.Type, Materials.Sequence, Materials.Material 'FROM(Materials) 'ORDER BY Materials.Type, Materials.Sequence; Try gblConn = New OleDbConnection(JWIConnStr) Dim daMaterial As New OleDbDataAdapter Dim dsMaterial As New DataSet Dim mySelectQuery As String = "SELECT MaterialsID, Type, Sequence, Material " & \_ "FROM Materials " & \_ "ORDER BY Type, Sequence;" Dim myConnection As New OleDbConnection(JWIConnStr) Dim myCommand As New OleDbCommand(mySelectQuery, myConnection) myConnection.Open() daMaterial.SelectCommand = myCommand daMaterial.Fill(dsMaterial) If Not dsMaterial.Tables(0).Rows.Count > 0 Then MsgBox("Unable to locate MATERIALS. Please Cancel and retry later", MsgBoxStyle.OkOnly) Exit Function Else 'at least one record shows Dim recCount As Integer Dim dstbl As New DataTable daMaterial.Fill(dstbl) recCount = dsMaterial.Tables(0).Rows.Count Dim rowNdx As Integer Dim lblNdx As Integer rowNdx = 0 'Set to zero index value for the dsMaterial tbl lblNdx = 1 For Each Row In dstbl.Rows
tell your IDE to always display line numbers (Visual Studio Tricks[^]). go to the offending line. take the message literally: some argument is null where it should not be. now fix it. if you still don't see it, use a debug run, and watch the values in the offending line. :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
-
tell your IDE to always display line numbers (Visual Studio Tricks[^]). go to the offending line. take the message literally: some argument is null where it should not be. now fix it. if you still don't see it, use a debug run, and watch the values in the offending line. :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
I have no problem picking up the line number and col number from the bottom of the IDE. It very clearly shows it. What I am not understanding is WHY the code is not returning the controlType? This loop (line numbers added for your convienance) from lines 43 to 56 should pick up the type as being a Label from what was defined and pased into it. I would imagine that is what appears to be Null - it doesn't pick up that lblRods_ is a label even though I have tried both of these combinations: Dim Labels As Label() = ControlArrayUtils.getControlArray(Me, "lblRods") Dim lblRods As Label() = ControlArrayUtils.getControlArray(Me, "lblRods") and I don't know how many other combinations. My conclusion is an error in the original code- but that is because I am not certain. I would hope somebody with more experience than myself would be able to examine and determine if that is the case and possible suggest a solution. I'm assuming it would return the controlType as Label and not Null
43 If maxIndex > -1 Then
44
45 For i = 0 To maxIndex
46 Dim aControl As Control = _
47 getControlFromName(frm, controlName, i, separator)
48 If Not (aControl Is Nothing) Then
49 'Save the object Type (uses the last
50 'control found as the Type)
51 controlType = aControl.GetType
52 End If
53 alist.Add(aControl)
54 Next
55 End If
56 Return alist.ToArray(controlType) -
I have no problem picking up the line number and col number from the bottom of the IDE. It very clearly shows it. What I am not understanding is WHY the code is not returning the controlType? This loop (line numbers added for your convienance) from lines 43 to 56 should pick up the type as being a Label from what was defined and pased into it. I would imagine that is what appears to be Null - it doesn't pick up that lblRods_ is a label even though I have tried both of these combinations: Dim Labels As Label() = ControlArrayUtils.getControlArray(Me, "lblRods") Dim lblRods As Label() = ControlArrayUtils.getControlArray(Me, "lblRods") and I don't know how many other combinations. My conclusion is an error in the original code- but that is because I am not certain. I would hope somebody with more experience than myself would be able to examine and determine if that is the case and possible suggest a solution. I'm assuming it would return the controlType as Label and not Null
43 If maxIndex > -1 Then
44
45 For i = 0 To maxIndex
46 Dim aControl As Control = _
47 getControlFromName(frm, controlName, i, separator)
48 If Not (aControl Is Nothing) Then
49 'Save the object Type (uses the last
50 'control found as the Type)
51 controlType = aControl.GetType
52 End If
53 alist.Add(aControl)
54 Next
55 End If
56 Return alist.ToArray(controlType)From the MSDN documentation on ArrayList.ToArray(Type) it is clear an ArgumentNullException will be thrown when the type is Nothing. So here are two ways to get that, assuming controlType starts at Nothing: 1. the if fails in line 43 2. getControlFromName in line 47 return Nothing for any of a million reasons (maybe controlName does not contain what you hope for) I must say your code snippet (lines 43-56) is a bit bizarre; either you expect to find a single control, then why would you need an ArrayList? or you expect multiple controls, but then the last one decides on the type of all of them?? This could work fine under your current conditions, I can't tell, it doesn't look very robust. And, as stated before, there may be zero matches, resulting in line 56 causing an Exception. FWIW: I advise you start each VB file with "Option Strict On". It will cause some pain as now the system complains a lot, but it will force you to improve your code and in the end save lots of debugging time. :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
-
I have a table of 13 items that I need to display in sequence. The sequence can change from day to day based upon the previous days usage. One day the number 1 item may be 3/4" concrete lined rod, the next day that may be 5th and 5/8" SMPC may be the number one item. I pull the material from the table in the sequence order and then I want t fill in the label with the material name and the label tag property with the MaterialID which is a GUID. I found some code in a google search for creating a control array but I'm just not understanding it enough to get it to work in my project. The link for that is as follows: http://vbnet.codenewbie.com/articles/vbnet/1555/Mimicking\_VB6\_Control\_Arrays\_in\_VBNET-Page\_1.html My labels are named lblRods_0 to lblRods_12 and the code for loading them is:
Private Function LoadTabData() As Boolean 'We need to get the items for the frmLOL from the table Materials and load 'them into the text boxes in sequence. If user fills out anything we need to 'store it using the GUID stored in the tag property 'SELECT Materials.MaterialsID, Materials.Type, Materials.Sequence, Materials.Material 'FROM(Materials) 'ORDER BY Materials.Type, Materials.Sequence; Try gblConn = New OleDbConnection(JWIConnStr) Dim daMaterial As New OleDbDataAdapter Dim dsMaterial As New DataSet Dim mySelectQuery As String = "SELECT MaterialsID, Type, Sequence, Material " & \_ "FROM Materials " & \_ "ORDER BY Type, Sequence;" Dim myConnection As New OleDbConnection(JWIConnStr) Dim myCommand As New OleDbCommand(mySelectQuery, myConnection) myConnection.Open() daMaterial.SelectCommand = myCommand daMaterial.Fill(dsMaterial) If Not dsMaterial.Tables(0).Rows.Count > 0 Then MsgBox("Unable to locate MATERIALS. Please Cancel and retry later", MsgBoxStyle.OkOnly) Exit Function Else 'at least one record shows Dim recCount As Integer Dim dstbl As New DataTable daMaterial.Fill(dstbl) recCount = dsMaterial.Tables(0).Rows.Count Dim rowNdx As Integer Dim lblNdx As Integer rowNdx = 0 'Set to zero index value for the dsMaterial tbl lblNdx = 1 For Each Row In dstbl.Rows
I have to agree...that is some bizarre code. So, you have 13 labels that all start with lblRods. So then, you're running the function to return an array of controls that all start with lblRods. All of that is great. Your problem is with the getControlArray code. Think about what it should do and then look at exactly what it does. It should loop through all of the controls on the form and see if the control starts with the value you passed in, in this case "lblRods". If it does start with that, then you want to add it to the array. Here's what your code does. You search through the controls and are looking for the highest index of the controls. So, your code matches each control that starts with lblRods and instead of adding that control to an array, you instead, see if it's index is the highest index so far. Then, if the index is greater than -1, you go through and call GetControlFromName which will return a control with the exact name that you passed it. In this case, you passed it lblRods. It will never return a control with that exact name because it doesn't exist. So, what happens is that aList will have nothing in it and controlType will equal
Nothing
. Why didn't you just add the controls to the list when you found them in the first for each loop? That's all you needed to do. And you need to make sure that the array isn't empty before returning something. How about a re-write:Public Shared Function getControlArray(ByVal frm As System.Windows.Forms.Form, _
ByVal controlName As String, _
ByVal TypeToReturn As Type, _
Optional ByVal separator As String = "") As Control()
Dim aList As New ArrayListFor Each ctrl As Control In frm.Controls If ctrl.Name.ToLower.StartsWith(controlName.ToLower & separator) And \_ ctrl.GetType = TypeToReturn Then aList.Add(ctrl) End If Next If aList.Count = 0 Then Return Nothing Else Return aList.ToArray(TypeToReturn) End If
End Function
it's that easy...you were making it too complicated. If you're only wanting to return a single type, then you really need to make sure to check that that type is the right type. Obviously, you can know that the only thing with the name "lblRods" is going to be a label because you wrote it that way, but then why not just hard code the values, unless you're tryin
-
I have to agree...that is some bizarre code. So, you have 13 labels that all start with lblRods. So then, you're running the function to return an array of controls that all start with lblRods. All of that is great. Your problem is with the getControlArray code. Think about what it should do and then look at exactly what it does. It should loop through all of the controls on the form and see if the control starts with the value you passed in, in this case "lblRods". If it does start with that, then you want to add it to the array. Here's what your code does. You search through the controls and are looking for the highest index of the controls. So, your code matches each control that starts with lblRods and instead of adding that control to an array, you instead, see if it's index is the highest index so far. Then, if the index is greater than -1, you go through and call GetControlFromName which will return a control with the exact name that you passed it. In this case, you passed it lblRods. It will never return a control with that exact name because it doesn't exist. So, what happens is that aList will have nothing in it and controlType will equal
Nothing
. Why didn't you just add the controls to the list when you found them in the first for each loop? That's all you needed to do. And you need to make sure that the array isn't empty before returning something. How about a re-write:Public Shared Function getControlArray(ByVal frm As System.Windows.Forms.Form, _
ByVal controlName As String, _
ByVal TypeToReturn As Type, _
Optional ByVal separator As String = "") As Control()
Dim aList As New ArrayListFor Each ctrl As Control In frm.Controls If ctrl.Name.ToLower.StartsWith(controlName.ToLower & separator) And \_ ctrl.GetType = TypeToReturn Then aList.Add(ctrl) End If Next If aList.Count = 0 Then Return Nothing Else Return aList.ToArray(TypeToReturn) End If
End Function
it's that easy...you were making it too complicated. If you're only wanting to return a single type, then you really need to make sure to check that that type is the right type. Obviously, you can know that the only thing with the name "lblRods" is going to be a label because you wrote it that way, but then why not just hard code the values, unless you're tryin
Thanks, the last two replies help me to understand what is going on a little bit better. I'm wanting an easier way to handle this. I have a tab on the form with 4 tabs and on each tab the number of items that will vary from day to day : 13 Rods, 11 Tubes, 10 Equip, and 9 Misc. So hard coding it is not really desirable. I wonder if it shows Null or nothing as a result of the labels being on the tab. When I ran this:
For Each Row In dstbl.Rows If rowNdx = recCount Then Exit For End If For Each c As Control In Me.TabPage1.Controls If c.Name = "lblRods\_" & lblNdx Then c.Tag = dsMaterial.Tables(0).Rows(rowNdx)("MaterialsID").ToString() c.Text = dsMaterial.Tables(0).Rows(rowNdx)("Material").ToString() End If Next rowNdx = rowNdx + 1 'keep track of where we are at lblNdx = lblNdx + 1 Next
It did not work as For Each c As Control In Me.Controls Debug.Print showed me the names of each control but I just got tabLOL but not tabLOL.TabPage1 so when I hard coded it fills in properly. So I changed to having 4 separate functions: Private Function LoadTab1Data() As Boolean Private Function LoadTab2Data() As Boolean Private Function LoadTab3Data() As Boolean Private Function LoadTab4Data() As Boolean And it seems to be working when I change the statement:
Dim mySelectQuery As String = "SELECT MaterialsID, Type, Sequence, Material " & \_ "FROM Materials " & \_ "WHERE Type = 2 " & \_ "ORDER BY Type, Sequence;"
and change the Type. Would still like to modularize it more and make it one Function that goes through the data 4 times and fills in each tab page properly. Works clumsily now, but still hoping to refine it, Larry
-
Thanks, the last two replies help me to understand what is going on a little bit better. I'm wanting an easier way to handle this. I have a tab on the form with 4 tabs and on each tab the number of items that will vary from day to day : 13 Rods, 11 Tubes, 10 Equip, and 9 Misc. So hard coding it is not really desirable. I wonder if it shows Null or nothing as a result of the labels being on the tab. When I ran this:
For Each Row In dstbl.Rows If rowNdx = recCount Then Exit For End If For Each c As Control In Me.TabPage1.Controls If c.Name = "lblRods\_" & lblNdx Then c.Tag = dsMaterial.Tables(0).Rows(rowNdx)("MaterialsID").ToString() c.Text = dsMaterial.Tables(0).Rows(rowNdx)("Material").ToString() End If Next rowNdx = rowNdx + 1 'keep track of where we are at lblNdx = lblNdx + 1 Next
It did not work as For Each c As Control In Me.Controls Debug.Print showed me the names of each control but I just got tabLOL but not tabLOL.TabPage1 so when I hard coded it fills in properly. So I changed to having 4 separate functions: Private Function LoadTab1Data() As Boolean Private Function LoadTab2Data() As Boolean Private Function LoadTab3Data() As Boolean Private Function LoadTab4Data() As Boolean And it seems to be working when I change the statement:
Dim mySelectQuery As String = "SELECT MaterialsID, Type, Sequence, Material " & \_ "FROM Materials " & \_ "WHERE Type = 2 " & \_ "ORDER BY Type, Sequence;"
and change the Type. Would still like to modularize it more and make it one Function that goes through the data 4 times and fills in each tab page properly. Works clumsily now, but still hoping to refine it, Larry
Your problem with that is what you thought it was. frm only knows about the controls added directly to it. Containers have their own controls and the object that the container is added to knows nothing directly about it's children. You can access it through Me.TabPage1 because it's a variable that was declared within the form, but it was never added to the forms control collection, it was added to the tabControl's control collection. If you want to be able to search through children controls as well, you could do that using a modified version of what I posted earlier.
Public Shared Function getControlArray(ByVal baseControl As Control, _
ByVal controlName As String, _
ByVal TypeToReturn As Type, _
Optional ByVal separator As String = "") As Control()
Dim aList As New ArrayListFor Each ctrl As Control In baseControl.Controls If ctrl.Controls.Count > 0 Then For Each item As Control In getControlArray(ctrl, controlName, TypeToReturn, separator) aList.Add(item) Next End If If ctrl.Name.ToLower.StartsWith(controlName.ToLower & separator) And \_ ctrl.GetType = TypeToReturn Then aList.Add(ctrl) End If Next Return aList.ToArray(TypeToReturn)
End Function
I just made the Form being passed in a Control instead and check that control for any children, then it recursively checks the children. I tested it by adding a TabControl and several Labels to a TabPage and it works as expected. You can also just pass in the TabPage if you know that the items will only be on that TabPage.