I want to display an unknown number of checkboxes on the page in the form of:
<input type="checkbox"... />
<label for...>
My database table has the information about these checkboxes
Id
Name
For simplicity let's say that Id is just an integer and Name is a colour ("Red", "Green").
How best can I generate these boxes?
My current code is
Model
Public Property Colours As IEnumerable(Of CheckBox)
Public Sub New()
Colours = ...
End Sub
View
#For Each item In Model.Colours
#Html.CheckBox(item.Text, item.Checked)
#Html.Label(item.Text, item.Text)
Next
Also, how are CheckBoxList and CheckBoxField supposed to be used?
I would consider using an extension to generate the check box list, rather than rolling it manually, such as:
CheckBoxListFor
Fabrik.commons
MVC Controls Toolkit
Some colleagues had a problem with previous versions of the MVC Controls Toolkit. That's just hearsay on my part as I was working on something different at the time but just thought I'd mention it in case YMMV.
Re: "how are CheckBoxList and CheckBoxField" supposed to be used, the way I look at it is:
CheckBoxList for a set of related options and you want people to select none, one or possibly more than one
CheckBoxField for when you have a single option which is yes/no or true/false in nature (e.g. a "tick me to unsubscribe" box)
HTH,
Nathan
Related
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)". (:
I just started rewriting an application from vba (Access) to vb.net + SQLServer so not very experienced in .net.
I am creating custom controls (Form + form controls) with a number of extra properties PrevValue, Modified (similar then the one of Textbox), Dirty, DirtyEnabled, SQLColumnName, SQLTableName to enable AutoUpdating and undoing in my forms the form exposes IsDirty, Initialising and Isready properties and an undo method.
Doing so it occurs that I have to write 3 times the same iteration code in different places:
For each Ctrl as Control in frm.Controls ' frm being a reference to the form
if typeOf Ctrl is MyTextBox
with DirectCast(Ctrl, MyTextBox)
' here comes the variable code depending what needs to be done
end with
elseif TypeOf Ctrl is MyComboBox
' etc.... for MyListBox, MyCheckBox etc....
I also have a number of custom controls MyNumBox and MyDateBox that inherit from MyTextBox but with some modified behavior (Formula evaluation, date manipulation, calendar...) how do I avoid doing an extra test on them.
One version of this Iteration is in the SQLProcessClass where the modified controls are added as SQLParameter and after iteration calling the SQLProcessClass Update or Insert, but ... after successful SQL activity I need to iterate through the controles again to reset the modified flag for each control. Elsewhere I need it to implement a form undo to reset all the controls to their previous values.
It seems to me I have two options
1. repeating that iteration code everywhere I need to iterate through the forms controls. I don't like it as every time I would need to create a new custom control I have to add some lines X times in different modules/classes ... very bad programming
2. Creating one form iteration procedure containing all the different activities that normally belong to another class within that "centralised" procedure, that could be better then (1) but I don't like it that much either.
Is there a better way of doing it using some .net functionality I don't master yet ?
Thanks for any advise.
Iterating through from controls can be tricky since controls are often nested. A more controlled approach would be to add another collection object to your form where you keep references to your added controls.....
e.g
Dim My_Widgets as New List(of Your-Control-Class-Name)
Then when you create the controls to the form also add them to that list.
My_Widgets.Add(Widget_Object)
After that it is a simple matter to iterate through that list.
For Each Widget as My_Widget_CLass in My_Widgets
' do what you need to do to Widget
Next
If you need to reference individual controls directly, use a dictionary object instead..
e.g.
Dim My_Named_Widgets as new Dictionary(of String, Your-Control-Class-Name)
Then add your control references to the dictionary by name
My_Named_WIdgets.add("<Whatever_You_USe_To_Identify_It>", Widget_Object)
You can then reference the specific control by the ID or name
My_Names_Widgets("ID").Property = Whatever '... etc
You seem to be indicating you have other controls for other purposes, as such it would be prudent to create similar collections for each type.
I have created a Userform with a ComboBox for purposes of entering client names and information about their children, their names addresses, etc. The data entered will be used to populate various legal documents, and in many cases the clients will select their children (and the children's information) repeatedly. Understanding this to be the case, I have each entry .AddItem'd to the ComboBox List as I enter the data. So far so good.
But I am now trying to set the MatchEntry property (or something else in a manner which will allow me to "find" a former entry in the list and then select it or override it). The MatchEntryFirstLetter property, if active and nothing matches it, won't allow a new entry, it just flashes-back with the letters I type. MatchEntryComplete forces me to use a former entry (for instance if I have earlier entered the client name in Lower Case, MatchEntryComplete finds the Lower Case name but won't let me override it with an UPPER CASE version. Ho-hum.
So before I struggle further (and abandon this to MatchEntryNone), is there a way to structure the ComboBox (or is there a form of VBA code) such that as I enter text in the ComboBox it will simply "search" for a match, and then release me to either select the match or override it with a new entry?
Thanks in advance for your answers.
Mike
AFAIK, ComboBox already have that feature.
You just need to:
set MatchEntry to 1 - fmMatchEntryComplete
set Style to 0 - fmStyleDropDownCombo which are actually the defaults.
Consider below:
Private Sub UserForm_Initialize()
Me.ComboBox1.List = Array("Entry1", "Option1", "Item3")
End Sub
Say we have a UserForm1 with 1 ComboBox named ComboBox1.
If we run the form, it will look like below after typing O and p.
If you type another letter say y, it will automatically be overwritten.
If the searched match already satisfies your search, the just move on to next control either by using mouse or Tab key. Is this what you're trying to do or did I misunderstood your question?
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
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