I would like to know if you can use one general if statement for the same condition but on multiple controls?
for example, If I have five labels and I want each label to say "hello" when I push a button I would write something like
If Label1.Text = "" Then
Label1.Text = "hello"
End If
But instead of writing an if statement for each label is there a way to apply this one if statement to all five labels?
Yes, you can iterate over all controls in a form, but you'd need to restrict them to Label instances, fortunately LINQ makes this easy:
Dim emptyLabels As IEnumerable(Of Label) = _
Me.Controls.OfType(Of Label)().Where(Function(l) l.Text.Length = 0)
For Each label As Label In emptyLabels
label.Text = "hello"
Next
You could do this:
Dim ifEmptyAssignHello As Action(Of Label) = _
Sub(l)
If l.Text = "" Then
l.Text = "Hello"
End If
End Sub
ifEmptyAssignHello(Label1)
ifEmptyAssignHello(Label2)
ifEmptyAssignHello(Label3)
Well you could
make a method which takes a label,
then pass labels into it.
Public Sub SayHello(l As Label)
If (l is Nothing) Then Return
If (l.Text = "") Then
l.Text = "Hello"
End If
End Sub
...
For Each l As Label in anyLabels
SayHello(l)
End For
The most concise way to do what you describe is to iterate over an explicit array of the labels. VB.Net will notice that they're all Labels and figure out the type for you.
For Each individualLabel In {Label1,
Label2,
Label3,
Label4,
Label5}
If individualLabel.Text = "" Then individualLabel.Text = "hello"
Next
Of course, if you need to do this more than once, you'll want to define a variable to refer to that particular group of five labels.
Dim myFiveLabels As IEnumerable(Of Label) = {Label1, Label2, Label3, Label4, Label5}
(We explicitly define the variable as an IEnumerable because this way it can only be used to iterate over each element of the group. If it were defined as an Array or List, you could e.g. add / remove elements and generally complicate its behaviour.)
Related
I'm trying to sort list of Controls by their name. This is my code to loop through Form Controls and add them to list.
Public Sub FindControls(ByVal owner As Control, ByVal list As List(Of Control), ByVal name As String)
'list.Clear()
For Each c As Control In owner.Controls
If c.Name.Contains(name) And c.Name.Length < 4 Then
list.Add(c)
End If
If c.HasChildren Then FindControls(c, list, name)
Next
End Sub
Then i want to loop through this list and get value from these controls by index.
For i As Integer = 0 To ElektrikList.Count - 1
If ElektrikList(i).Name = "T" & i.ToString Then
'do something
End If
Next
I named all my controls "T00" (example: "T1" or "T50"), but they are added to the list with wrong order, so for example index 4 in this List is T23, not T4 as I would wish.
Is there any way to sort it? I tried everything i found but I can't get it to work.
At first i tried to create all these controls dynamically, but I want to add them on different Panels with categories and so on, so i thought it would be really painful to make this.
Would something like this work?
Dim sorted = From ctrl In owner.Controls
Order By ctrl.Name
For Each c As Control In sorted
(...)
I followed the example from Introduction to LINQ in Visual Basic.
I named all my controls "T00" (example: "T1" or "T50"), but they are
added to the list with wrong order
If you're only interested in those specific controls, then search for them in that order using the recurse option of Controls.Find() and add them to your list:
Public Function FindControls() As List(Of Control)
Dim ctrls As New List(Of Control)
For i As Integer = 1 To 50
Dim ctrlName As String = "T" & i.ToString("00")
Dim ctrl As Control = Me.Controls.Find(ctrlName, True).FirstOrDefault
If Not IsNothing(ctrl) Then
ctrls.Add(ctrl)
End If
Next
Return ctrls
End Function
Si I'm working on an assignment where I have 10 RadioButtons indicating how many contesters I have, and depending on what I pick between 1 to 10, I need that many of my corresponding TextBoxes to be enabled so I could fill it with names!
Is there a way for me to make a For loop between 1 and the number I picked from the RadioButton and say something like
For i = 0 to Size
{
TextBox&i.Enabled = True
}
Since my TextBoxs are called TextBox1 to TextBox10
I know you can add strings together using &, but how can I do that for an object name?
As of right now I literally have the dumbest way of doing it, which is a click event inside each RadioButton that manually enables the correct number of TextBoxes...
Thank you in advance!
You can iterate over all controls like this:
For Each ctr In Me.Controls
Dim indx As String = ctr.Name
If TypeOf (ctr) Is Textbox Then
' Now compare the name with TextBox&i and do smth
End If
Next
It's not possible to just concatenate a string and use it as an object variable reference like that, but you can search the form's controls by their name property (which is a string) and do it that way. Here's an example:
Private Sub EnableTextBoxes(ByVal Size As Integer)
For i As Integer = 1 To Size
Dim matches() As Control = Me.Controls.Find("Textbox" & i.ToString, True)
If matches IsNot Nothing AndAlso matches.Length = 1 Then matches(0).Enabled = True
Next
End Sub
Since i needed to disable (grey out) some items inside a ListBox, i'm using a Custom control that can be found here:
Here is my current code:
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtp.Columns.Add("key")
dtp.Columns.Add("value")
PopulateDataTable(dtp, "myTxt")
_dataView = New DataView(dtp)
'Custom ListBox
List1.ValueMember = "key"
List1.DisplayMember = "value"
List1.DataSource = _dataView
'Legacy ListBox
List2.ValueMember = "key"
List2.DisplayMember = "value"
List2.DataSource = _dataView
UpdateLanguageMenu()
End Sub
Private Function PopulateDataTable(dt As DataTable, resTxt As String)
Using sw As New StringReader(My.Resources.ResourceManager.GetObject(resTxt))
Do
Dim line As String = sw.ReadLine
If line Is Nothing OrElse line.Trim = String.Empty Then Exit Do
Dim strArr() As String
strArr = line.Split(",")
Dim row As DataRow = dt.NewRow()
row("key") = strArr(0)
row("value") = strArr(1)
dt.Rows.Add(row)
Loop
sw.Close()
End Using
End Function
List1 is the Custom ListBox and List2 is the ListBox that comes with VS2012E.
I don't need List2, it's only there to test,
and at runtime, in List2 i get all my values loaded correctly, instead in List1 i get System.Data.DataRowView in all rows..
The strange thing is that, my txt i'm loading is like:
00A1,MyValue1
00A2,Myvalue2
00A3,MyValue3
I have also a Label, and when selecting items on the ListBox i have code to change the Label.Text to List.SelectedValue that is the first part before the comma.
And it get displayed in the label. Only items inside the Custom ListBox are not being displayed.
Populating List1 manually, instead using a DataTable, is working.
And since i'm a beginner i can't locate the problem.
I think your problem has to do with this line: string displayValue = GetItemText(item); in the control. This takes for granted that all items are strings. In your case it is a datarowview hence the result (drv.toString would return something like that). You need to convert "item" into a drv and set display value to be drvItem("value" or "key") instead. So it is basically not your code that is the problem, it is the control.
Actually... After reading the code in the control and not on the code project site, I realised that this line:
displayValue = GetItemText(item);
Doesn't even exist. It is exchanged with
item.ToString()
Which pretty much proves my theory.
Right, how to fix.
In:
protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
You have this:
object item = this.Items[e.Index];
What you have to do is to convert item into a DataViewRow and assign value to a variable, something like this:
DataViewRow dvrItem = (DataViewRow)item;
String displayText = dvrItem("key"); or String displayText = dvrItem("value");
Then change all these:
e.Graphics.DrawString(item.ToString(), e.Font, SystemBrushes.GrayText, e.Bounds);
Into:
e.Graphics.DrawString(displayText, e.Font, SystemBrushes.GrayText, e.Bounds);
I have several label boxes on my design form that all share the naming convention lbl_#.text where # ranges from 1 to 60. I want to make a loop that iterates through each lbl_#.text adding some incremental value, let's say multiples of 2 for this question's theoretical purpose.
Something such that the end result would amount to the following:
lbl_1.text = "2"
lbl_2.text = "4"
lbl_3.text = "6"
...
lbl_60.text = "120"
I'm not sure how to access each of these labels through the coding side, I only know how to explicitly mention each label and assign a value :/
There are a few options here.
In this situation the labels will often have a common container, such as panel or groupbox control. In that case:
Dim formLabels = myContainerControl.Controls.OfType(Of Label)()
For Each formLabel As Label In formLabels
'...
Next formLabel
Of course, this mixes logical groups with visual groupings. Those two things don't always align well, so you can also...
Add them all to a Label array (or List(Of Label) or any other enumerable):
Dim formLabels(60) As Label = {lbl_1, lbl_2, lbl_3 .... }
For Each formLabel As Label in formLabels
'...
Next formLabel
But sometimes that's more trouble than it's worth, even if you use a loop to create the collection, and so you can also
Use the .Name property (in conjunction with a naming convention to identify your desired controls):
Dim formLabels = Controls.Where(Function(c) c.Name.StartsWith("lbl_"))
For Each formLabel As Label In formLabels
'...
Next formLabel
Some combination of the above (for example, code in the form load event to create a list based on the name property).
Notice the actual For Each loop is exactly the same in all of those options. No matter what you do, get to the point where you can write a single expression to identify the label control, and then run a simple loop over the expression result.
This points to a final strategy: think in terms of binding to a data source. With a data source, your labels are created as part of a DataGridView, FlowLayoutPanel, or similar control. Then you can iterate the rows in the grid or panel.
Use the Controls collection:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim i As Integer
For i = 1 To 3
Dim myLabel As Label = CType(Me.Controls("lbl_" & i), Label)
myLabel.Text = ...whatever value you want to put here
Next
End Sub
End Class
If you don't know how many labels there are, one option is to use a Do Loop.
Dim lblTarget As Label = Nothing
Dim intCursor As Integer = 1
Dim bolFirstIteration As Boolean = True
Do Until lblTarget Is Nothing AndAlso Not bolFirstIteration
If bolFirstIteration Then
bolFirstIteration = False
End If
lblTarget = CType(Me.Controls("lbl_" & intCursor.ToString()), Label)
If Not lblTarget Is Nothing Then
lblTarget.Text = (intCursor * 2).ToString()
End If
intCursor += 1
Loop
I have 6 different text boxes with similar names:
txtBox1, txtBox2....txtBox6
I also have an array:
dim intValue (0 to 5) as Integer
Now I want to use a for loop to assign the value in each text box to a corresponding space in the array, concatenating the value of the loop counter with the string "txtBox" and retrieving the data using the .text method.
here is my code:
For count As Integer = 0 To 5
Dim strCount As String = count
Dim strTxtBox As String = "txtBox" & strCount
intValues(count) = Convert.toInt32(strTxtBox.Text)
Next
the issue is that the string name doesn't point to txtBox1, txtBox 2 etc.
Thanks in advance for the help.
If you want to access the control name, you have to use the property "Name".
You should try something like that:
For i As Integer = 0 To 5
For Each c As Control In Controls
If c.Name = "txtBox" & i Then
intValue(i) = Convert.ToInt32(c.Text)
End If
Next
Next i
The above code is just an example, but it should work for you.
Anyway you can write a better code checking the type of the control or maybe using a different loop logic, but the basic idea is that if you want to use in your code the name od the control you have to use the NAME property.
strTxtBox is a string, nothing more. You cannot refer to control names by String without special code. Rather than go down that path, I'd create an array and populate it with text boxes:
Dim txtBoxes As TextBox() = {txtBox1, txtBox2, txtBox3, txtBox4, txtBox5, txtBox6}
Dim intValues As Integer(0 To 5)
For count As Integer = 0 To 5
intValues(count) = Convert.ToInt32(txtBoxes(count).Text)
Next
The easiest way is to iterate through the contents of Controls to find the textboxes. You can either:
Use the .Tag property to label textboxes to identify them, or as the other answer points out, use the .Name property.
If you have a lot of other controls on the form, and they may not be in order, you could also check each control to see if it's a textbox. Assume they are in reverse order, as the Controls array goes from end to beginning.
Dim nums() As Integer = {10, 20, 30, 40, 50, 60}
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeOf (ctrl) Is TextBox Then
ctrl.Text = nums(Val(ctrl.Name(ctrl.Name.Length - 1)) - 1)
End If
Next
You could also instantiate an array of textboxes programmatically, but you'd have to set all of the placement, etc. by hand.
As I commented on the answer below, you may need to cast the ctrl to a System.Web.UI.Control to access the .Name, using DirectCast.