Load comboboxes with one line of code? - vb.net

I have around 15 comboboxes on my form, all being loaded with the same information pulled from a table(~150 entries). Currently I am taking the information from the table, then looping through the entries and adding them to each textbox. I'm wondering if there's a more efficient way to load these comboboxes then having to individually add the table entry into each combobox, having to list 15 lines of code within the For loop.
I'm not seeing any performance issues with this, but figured I might as well work with the most efficient way possible rather than stick with what works. :)

You can create a list of the combo boxes, and then just loop through them. For instance:
Dim cbos() As ComboBox = {ComboBox1, ComboBox2, ComboBox3}
For Each cbo As ComboBox In cbos
' Load cbo from table
Next
Alternatively, if they are named consistently, you could find the combo box by name:
For i As Integer = 1 to 15
Dim cbo As ComboBox = DirectCast(Controls("ComboBox" & i.ToString())), ComboBox)
' Load cbo from table
Next

Since Combobox items are a collection, if their elements are the same, you can build and array with the objects you want to insert, and then just insert this array to each ComboBox with the method AddRange() (it's a method which exists inside the Combobox.items).
Getting an example from MSDN:
Dim installs() As String = New String() {"Typical", "Compact", "Custom"}
ComboBox1.Items.AddRange(installs)
Then you would only have to do a loop to add the array to each ComboBox. Of course, you will need to build your array first on your own, instead of this easy string array from the example.
Reference:
MSDN - AddRange

You could also do it this way since you mentioned that you already have a table.
Use a datatable
Change your table object into a datatable, which will assist in binding to the comboboxes. It might help if you add the datatable to a dataset too. That way you can attach all ComboBoxes (which are UI elements that let users see information) to the same DataSource, which is the datatable, in the dataset.
Binding
Now all you need to do is loop through all the comboboxes and set the datasource to the same table, that is if you decide to do it programmatically like so:
ComboBox1.DataSource = ds.Tables(0)
ComboBox1.ValueMember = "au_id"
ComboBox1.DisplayMember = "au_lname"
A further tutorial on this with the example above is found here
You can then also get the user selected value with ComboBox1.selectedValue.
On the other hand, if you did this with C# WPF, you can bind each comboBox in the XAML directly, I am unsure if this can be done in VB.net as I tried to look for the option but did not manage to do so, something you might want to try though.
Some very useful tutorials and guides on Data binding, which you might be interested:
~ denotes recommended reading for your question
MSDN: Connect data to objects
DotNetPerls on DataGridView (note this isn't a combobox, just displaying values)
~ VBNet DataTable Usage from DotNetPerls (this is in relation to 1.)
~ SO Q&A on Binding a comboBox to a datasource
Concepts of Databinding

Related

Fill a boolean array from checkbox control array

My program creates an array of checkboxes at runtime as shown below:
For Looper = 0 To 36
Dim Ex1ConfigCheck As New CheckBox
frmSetup.Controls.Add(Ex1ConfigCheck) ' Add Control to from
Ex1ConfigCheck.Top = (Looper + 45) + (Looper * 18) ' Set Location
Ex1ConfigCheck.Left = 210
Ex1ConfigCheck.Text = Setup.ExCheckName(Looper) ' Set Text property from strArray
Next
This is where I don't know how to proceed.
I would like to fill a boolean array (ex. MyBoolean(37)) with the value of Ex1configCheck().Checked. The reason I would like to fill another array is because I need to be able to reference the value of the checkboxes in other parts of the code but can't access them until they are created. Also, I plan on saving the array out to a binary file.
Could someone point me in the right direction please?
If there are no other CheckBoxes in the same container as those ones then you can do this:
Dim flags = Me.Controls.OfType(Of CheckBox)().
Select(Function(cb) cb.Checked).
ToArray()
If the controls are in a different container than the form itself, replace Me with that container.
As suggested by #Jimi, you could also create a List(Of CheckBox) and assign that to a field, populating it when you create the controls. You can then use that list instead of creating one on demand:
Dim flags = myCheckBoxList.Select(Function(cb) cb.Checked).
ToArray()
Of course, if you know exactly how many CheckBoxes you are going to be adding, why do you need to wait until run time to create them? Why can't you create them at design time and then modify them at run time? You usually only create controls at run time if you don't know how many there will be until run time, but that seems not to be the case here.
Thanks all for your answers and comments. I always have a fear of being roasted when I ask what some may consider a simple question online.
I have found an alternative way of accomplishing my task. Instead of creating 8 "Arrays" of checkboxes, I have learned of a very simple control available called "CheckedListBox".
I really didn't need to create the checkboxes at runtime but was trying to find an easier way to create 8 groups of 37 checkboxes without having to manually name and set the properties of each one during design. I also wanted to be able to index them in my code to be able to update and read the value using simple loops. I could have done this by creating arrays of CheckBox but again, I would have had to manually initialize the arrays.
Once I found the CheckedListBox, I was able to accomplish what I want very quickly. I only had to set the properties of the 8 "groups" (CheckedListBox's) and fill them using the items property. The ListBox essentially created a List like Jimi suggested automatically and I can index thru each list with a loop as desired. Jimi's suggestion actually lead me to finding the CheckedListBox while I was searching for more information on using "List(of CheckBox)".
Sometimes talking to others helps me find the right questions to ask. Google was able to figure out what I wanted when I searched for "List(of CheckBox)". (:

Datagridview Invisible Columns - accessing data

Having set up a datagridview, bound to a bindingsource, I have to use the cellformatting to paint the cells various colours.
Since you cannot access a field or record via bindingsource on a cellformatting event, the only way I could access the data, is through a column such as the primary ID for example. (this is only for cellformatting, i have no problem accessing the ID through the bindignsource.current object).
So, once I have finished designing and testing my datagridview, I then switch various columns (ID) for this example, to visible=false to make the column invisible.
I now cannot access the column data through cellformatting. I have read on a number of pages listed by google that since datagridview doesnt render the columns, the values are unobtainable aside from a couple of alternatives such as :
.TAG
and datakeynames
I cannot find datakeynames under datagridview for winforms for some reason.
.tag doesnt seem to do anything as far as I can tell.
Since trying to use this from the cell formatting, I am unable to use
Select Case .Columns(e.ColumnIndex).DataPropertyName.ToLower
or
If Datagridview1.columns(e.columnindex).datapropertyname.tolower='id' Then
as the column is invisible...
Shame I cannot access the bindingsource through cellformatting, but there must be a way and there must be others who have had this issue.
Use DataBoundItem:
Dim drw As DataRow = DirectCast(DataGridView1.Rows(i).DataBoundItem, DataRowView).Row
(Assuming you've bound to a DataTable)

Clearing combobox dropdownlists from application

I am working on an assignment that requires a user to answer 20 questions( multiple choice ). I am using the DropDownList property so the user cannot input anything other than A, B, C, or D.
Basically, I have 20 comboboxes and I have a button that clears them, but the code I should obviously be a loop, but I am not sure how to do that.
As of now, my code looks like this:
cboQuestion1.Items.Clear()
cboQuestion2.Items.Clear()
...
cboQuestion20.Items.Clear()
If anyone could shed some light on this, I will be grateful.
All controls reside in the form's Controls collection, so one way would be to iterate that (assumes these CBOs are the only ones you wish to clear):
For Each cbo As ComboBox In Controls.OfType(Of ComboBox)
cbo.Items.Clear
Next
Another way is to store the names of the target controls in a List(of String). Think of this as a shopping list of the controls you wish to track or treat in some special way:
Private myCBONamesList As List(of String)
'...
myCBONamesList.Add("cboQuestion1")
' etc
' add many/all at once:
myCBONamesList.Addrange(New String(){"cboQuestion1", "cboQuestion2" ...etc})
The New String() creates a temp array containing the literal values listed (in {}) and the whole thing is passed to your List to populate it. To use it:
For Each s As String in myCBONamesList
Controls(s).Items.Clear
Next
This method allows you to target certain CBOs and leave others alone.
It may or may not be the best way, but you could add all of your combo boxes to a List and then iterate over the list to clear them all.
Just iterate over the Form's Controls collection.
Here is an example of iterating over the Forms Controls collection with filtering to make sure you don't accidentally clear a non-question ComboBox:
For Each cbo As ComboBox In Me.Controls.OfType(Of ComboBox)
If cbo.Name Like "cboQuestion*" Then
cbo.Items.Clear()
End If
Next
Edit: Or if you're into one-lining things:
For Each cbo As ComboBox In Me.Controls.OfType(Of ComboBox).Where(Function(x) x.Name Like "cboQuestion*")
cbo.Items.Clear()
Next

Can I page through grouped data in DataGridView?

I have a simple VB.NET 2008 app that helps users to edit fields in the database. Simple enough as a first "real" project in .NET, right?
For one table, I am currently using a DataGridView so it can be edited straight up. However, instead of offering the user the entire table, I'd like to group the data by the 'CompanyNumber' column and use a navigator to page through. In other words, I'd like the DataGridView to show me all the lines related to one company, then click the "next" arrow to show the next company, etc.
(I know I could do this with Xceed DataGrid, but I'm using Windows Forms not WPF, and I'd really prefer to do this with "pure" ADO.NET for this project.)
Update 2009-09-28:
So I have created a ComboBox filled from the same BindingSource, and configured its SelectedIndexChanged to change the Filter value on the DataGridView.
But still, filling the ComboBox--which should be easy!--continues to be a problem. I can either:
(a) fill it from the BindingSource, in which case I see multiples of each 'CompanyNumber' and I can't figure out a way to show only distinct values, or
(b) create another TableAdapter in the data source which is just a "Select DISTINCT CompanyNumber..." query, which mostly works, except that that first value of the list changes when I change the selection (e.g. if the ComboBox shows "100, 101, 102, 103" and I pick "102", then the list will show as "102, 101, 102, 103").
Any recommendations?
(Also, bonus if you can suggest how to make the BindingNavigator's arrows page through the 'CompanyNumber' filters instead of the items in the DataGridView... which is what I'd really like to see.)
What you could do is just force the DataGridView to sort CompanyName, this way all rows with the same company name are next to each other and the user can navigate the data grids with the paging that comes with it.
Alternatly, you could follow through with your combobox/DropDownList idea, which would be best. From what I understand when you select an item in the combobox everything in it changes?
Another way is to create two separate buttons, "Previous" "Next", that when clicked, will change the DataGridView's binding source to only show a certain company. You would need to store an array of company names, then store what the current DataGridView's binding source is displaying.
I ended up figuring it out myself, and the solution is clean and simple. Here are the basic steps:
create a DataView off of the table out of the DataSet
use the DataView.ToTable() method to create a new table filtered to only distinct values from the needed column ('CompanyNumber')
create a BindingSource which uses the new DataTable as its DataSource
bind the ComboBox to the new BindingSource
bind the BindingNavigator to the new BindingSource
Because the ComboBox and the BindingNavigator use the same BindingSource, they will update each other with the changes automagically.
Here's the rough code:
Private Sub CoNumsComboxBox_LoadData()
Dim dvCoNums As DataView, dtCoNums As DataTable
dvCoNums = New DataView(Me.ODBCDataSet.Tables("CompanyFundProfile"))
dvCoNums.Sort = "CompanyNumber ASC, FundNumber ASC"
dtCoNums = dvCoNums.ToTable("CompanyFundProfile", True, "CompanyNumber")
CoNums_BindingSource.DataSource = dtCoNums
CoNumsComboBox.DataSource = CoNums_BindingSource
CoNumsComboBox.DisplayMember = "CompanyNumber"
CoNumsComboBox.ValueMember = "CompanyNumber"
'attach handler which changes DataGridView1's filter when this changes
AddHandler ToolStripComboBox1.SelectedIndexChanged, AddressOf CoNumsComboBox_SelectedIndexChanged
CompanyFundProfile_BindingNavigator.BindingSource = CoNums_BindingSource
End Sub

How do I add records to a DataGridView in VB.Net?

How do I add new record to DataGridView control in VB.Net?
I don't use dataset or database binding. I have a small form with 3 fields and when the user clicks OK they should be added to the DataGridView control as a new row.
If you want to add the row to the end of the grid use the Add() method of the Rows collection...
DataGridView1.Rows.Add(New String(){Value1, Value2, Value3})
If you want to insert the row at a partiular position use the Insert() method of the Rows collection (as GWLlosa also said)...
DataGridView1.Rows.Insert(rowPosition, New String(){value1, value2, value3})
I know you mentioned you weren't doing databinding, but if you defined a strongly-typed dataset with a single datatable in your project, you could use that and get some nice strongly typed methods to do this stuff rather than rely on the grid methods...
DataSet1.DataTable.AddRow(1, "John Doe", true)
I think you should build a dataset/datatable in code and bind the grid to that.
The function you're looking for is 'Insert'. It takes as its parameters the index you want to insert at, and an array of values to use for the new row values. Typical usage might include:
myDataGridView.Rows.Insert(4,new object[]{value1,value2,value3});
or something to that effect.
When I try to cast data source from datagridview that used bindingsource it error accor cannot casting:
----------Solution------------
'I changed casting from bindingsource that bind with datagridview
'Code here
Dim dtdata As New DataTable()
dtdata = CType(bndsData.DataSource, DataTable)
If you want to use something that is more descriptive than a dumb array without resorting to using a DataSet then the following might prove useful. It still isn't strongly-typed, but at least it is checked by the compiler and will handle being refactored quite well.
Dim previousAllowUserToAddRows = dgvHistoricalInfo.AllowUserToAddRows
dgvHistoricalInfo.AllowUserToAddRows = True
Dim newTimeRecord As DataGridViewRow = dgvHistoricalInfo.Rows(dgvHistoricalInfo.NewRowIndex).Clone
With record
newTimeRecord.Cells(dgvcDate.Index).Value = .Date
newTimeRecord.Cells(dgvcHours.Index).Value = .Hours
newTimeRecord.Cells(dgvcRemarks.Index).Value = .Remarks
End With
dgvHistoricalInfo.Rows.Add(newTimeRecord)
dgvHistoricalInfo.AllowUserToAddRows = previousAllowUserToAddRows
It is worth noting that the user must have AllowUserToAddRows permission or this won't work. That is why I store the existing value, set it to true, do my work, and then reset it to how it was.
If your DataGridView is bound to a DataSet, you can not just add a new row in your DataGridView display. It will now work properly.
Instead you should add the new row in the DataSet with this code:
BindingSource[Name].AddNew()
This code will also automatically add a new row in your DataGridView display.