I'm trying to change a Label Text with Controls command, using this line
Controls("C_" & 0).Text = "Conta:"
But I get this error
"System.NullReferenceException"
If I delete this label and change it for a textbox (with same name "C_0"), it works! But I need to do this with a Label not a textbox...
This is because you do not have a control named C_0. I would suggest using ControlCollection.Find to get your control and then use a conditional If statement to check if the returned control exists:
Dim desiredControls() As Control = Me.Controls.Find("C_" & 0, True)
If desiredControls.Count = 0 Then
'No controls named C_0 found
ElseIf desiredControls.Count > 1 Then
'Multiple controls named C_0 found
Else
desiredControls(0).Text = "Conta:"
End If
Or if you simply wanted a one-liner then you would use:
Me.Controls.Find("C_" & 0, True).First().Text = "Conta:"
However, I would highly recommend that you use the conditional If statements so that you an exception isn't thrown if 0 controls are found.
Ok, I find the problem... This command wasn't working because it was inside a GroupBox.
Then the right code is
Me.Controls("GroupBox1").Controls("C_" & 0).Text = "123"
Thanks for everyone help!
Your problem is control.Controls only returns the controls directly inside the control. So you can use these extension methods. Put this in a Module:
<Extension>
Public Function ChildControls(parent As Control) As IEnumerable(Of Control)
Return ChildControls(Of Control)(parent)
End Function
<Extension>
Public Function ChildControls(Of TControl As Control)(parent As Control) As IEnumerable(Of TControl)
Dim result As New List(Of TControl)
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is TControl Then result.Add(CType(ctrl, TControl))
result.AddRange(ctrl.ChildControls(Of TControl)())
Next
Return result
End Function
Here is how you would use it:
' general option to return all controls, filter on name
Me.ChildControls().Single(Function(c) c.Name = "C_" & 0)).Text = "Conta:"
' generic option to return only Labels, filter on name
Me.ChildControls(Of Label)().Single(Function(c) c.Name = "C_" & 0)).Text = "Conta:"
This will work whether the Label is in the GroupBox or not, and if you move it to a different GroupBox, Panel, or back to the Form, without needing to change your code.
Related
I am creating a form in Access which will be used as an order sheet for classroom materials. I have the available resources listed and a text box next to the resource where the user inputs the quantity they desire.
My VBA code checks to see if any entries have been made by using the following. (I am using Nz() to allow for Null results):
QuantCheck = Nz(Box1.Value, 0) + Nz(Box2.Value, 0) + Nz(Box3.Value, 0)
Where "QuantCheck" is the variable I am using in the IF statement which begins the workflow:
If QuantCheck > 0 Then
I would like to clean this up by using some kind of loop statement, however I am not able to extract the .value from a string. I would love something like the following which I could incorporate into a loop:
"Box"&VariableNumber.Value
From what I can tell, I am not able to use a string (concatenated or otherwise) as the base for the .value call.
It is interesting that there is a way to accomplish this when using a SQL statement. I have this elsewhere in the code which works nicely:
SQLStr = "INSERT INTO OrderRequests VALUES (cbSchool, txtName, Title" & x & ".caption, Box" & x & ")"
Here I have a variable "x" which increases with each loop to change the Title line, and the Box line.
Any help is appreciated.
I suggest you use the Tag property of the controls. Put "QuantCheck" in the Tag property of any control you want to include. Then
Function QuantitiesExist(frm As Form) As Boolean
Dim Ctrl As Control
Const sQUANTCHK As String = "QuantCheck"
For Each Ctrl In frm.Controls
If Ctrl.Tag = sQUANTCHK Then
If Nz(Ctrl.Value) > 0 Then
QuantitiesExist = True
Exit For
End If
End If
Next Ctrl
End Function
Now you get self documenting code
If QuantitiesExist(Me) Then
And when you add/delete/change controls, you don't have to edit your code. Just set up new controls with the proper tags.
You could loop through the control on the for checking the names and then if it is the one you wanted take an action on it, is this what you was thinking of?
Dim Ctrl As Control
For Each Ctrl In Me.Controls
If Ctrl.Name = "TxtPath" Then ' "Box" & VariableNumber Then
MsgBox Ctrl.Value
End If
Next
I have multiple TextBox controls Monday that will hold a value. I want to be able to add up all of the Monday textboxes and store that value as monTotal. I am getting an error message that says string cannot be converted to integer.
For i As Integer = 1 To rowCount Step 1
Dim var As Object
var = "txtMonday" & i & ".Text"
monTotal = monTotal + CInt(var)
Next
The way you are attempting to obtain a reference to the text boxes is not idiomatic of VisualBasic .NET.
var = "txtMonday" & i & ".Text" ' this is not a way to obtain a reference to the text box's text
While it would be possible to accomplish something like that using reflection, you'd be much better off refactoring your code to use an array of text boxes.
Since you are probably using Windows Forms you could perhaps implement logic to find the text box control you are interested in on the form using something like this:
' assuming container is the control that contains the text boxes
For Each ctrl In container.Controls
If (ctrl.GetType() Is GetType(TextBox)) Then
If ctrl.Name.StartsWith("txtMonday") Then
Dim txt As TextBox = CType(ctrl, TextBox)
monTotal = monTotal + CInt(txt.Text)
End If
End If
Next
The example above assumes that all the txtMonday.. text boxes are placed inside a control named container. That could be the form itself, or some other panel or table.
If all the textboxes live on the form and there are none being used for other text work you could use this. You could place all the textboxes that contain values your looking for in a separate container and get them like below, but use that control collection.
Dim amount As Double = 0
For Each tb As Textbox In Me.Controls.OfType(Of Textbox)()
amount += Convert.ToDouble(tb.Text)
Next
Dim monTotal as double=0
For Each ctrl As Control In Me.Controls
If TypeOf ctrl Is TextBox AndAlso ctrl.Name.StartsWith("txtMonday") Then
monTotal = monTotal + val(ctrl.Text)
End If
Next
I have created a function to translate my forms. I can loop through every control in a form to call this function, but I have made a situation, I cannot handle.
In one of my forms, I have groupbox in a groupbox.
This source works if I only have one groupbox.
Public Function translate_form(ByVal form As Form)
Dim control As Object
Dim controlname As String
form.Text = Get_Control_Name(form.Name, "Form")
Try
For i = 0 To form.Controls.Count - 1
control = form.Controls(i)
If TypeOf (control) Is MenuStrip Then
For j = 0 To control.items.count - 1
control.items(j).text = Get_Control_Name(form.Name, "MenuItem" & j)
Next
Else
controlname = Get_Control_Name(form.Name, control.Name)
control.Text = IIf(controlname Is Nothing, control.Text, controlname)
If TypeOf (control) Is GroupBox Then
For j = 0 To control.Controls.Count - 1
controlname = Get_Control_Name(form.Name, control.Controls(j).Name)
control.Controls(j).Text = IIf(controlname Is Nothing, control.Controls(j).Text, controlname)
If TypeOf (control.Controls(j)) Is Button Then
control.Controls(j).AutoSize = True
End If
Next
End If
If TypeOf (control) Is Button And UCase(control.Text) <> "X" Then
control.AutoSize = True
End If
End If
Next
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
End Try
End Function
But in some cases I want to sperate controls inside a container. I could have one more loop if the
control.Controls(j)
is a groupbox but I want to make this function to handle any kind of "container pyramid", if you know what I mean. Maybe I will have a container which has one also and that one too etc... Or is there any control I can use as a groupbox but it doesn't count as a contaier, so I can see it with:
form.Controls
Any suggestions?
Thanks in advance.
The reason why your code does not deliver what you want is that you are not performing a recursive search of controls. Bear in mind that Form.Controls contains only the parent controls (not the children controls eventually contained by the parents; like the situation you refer of controls contained by a GroupBox). Additionally, I see various not-too-right issues (you should writeOption Strict On on the top of your file) and that's why this answer intends to provide you with a somehow better framework to work with (you have just to fill in the blanks with your code):
Public Sub translate_form2(ByVal form As Form)
Try
For Each ctrl As Control In form.Controls
actionsCurrentControl(ctrl)
recursiveControls(ctrl)
Next
Catch ex As Exception
End Try
End Sub
'Accounting for all the child controls (if any)
Public Sub recursiveControls(parentControl As Control)
If (parentControl.HasChildren) Then
For Each ctrl As Control In parentControl.Controls
actionsCurrentControl(ctrl)
recursiveControls(ctrl)
Next
End If
End Sub
Public Sub actionsCurrentControl(curControl As Control)
If TypeOf curControl Is MenuStrip Then
Else
If TypeOf (curControl) Is GroupBox Then
End If
If TypeOf (curControl) Is Button And UCase(curControl.Text) <> "X" Then
End If
End If
End Sub
translate_form2 iterates through all the parent controls as in your code (but by relying on a set of Subs (you are wrongly using a Function without returning any value, what is wrong), making the structure more adaptable); it also calls recursiveControls (which also calls itself for each control it analyses) to take care of any child control which might be present. I am also including actionsCurrentControl which contains all the actions to perform for each control (you have to populate it with your code).
Please, can anyone help me with this problem:
I have a name(s) of control(s) in string format (str) and I want to set property (in code) of that controls using that string-name.
I try something like this but it doesn't work. Actually, I have a problem with expression. When I put exactly the name it works but when i use variable in string format it doesn't.
Dim str as String
str="k3"
Dim g As Image = CType(str, Image)
g.Source = New BitmapImage(New Uri("/APP;component/Icons/hero.png", UriKind.Relative))
This works:
Dim g As Image = CType(k3, Image)
While this does not:
Dim g As Image = CType(str, Image)
I think I understand what you are trying to do, to declare an object by a string...
Essentially for this to work you will need a custom function that returns the Object Type that you are seeking...
You will need to loop through each control and check the name of the control as a comparison, e.g. If oControl.Name.ToString = sString then Return oControl
Example
' A function to return a Control by the Control's name...
Public Function GetControlByName(ByVal oForm As Form, ByVal sName As String) As Control
Dim cReturn As New Control
Dim ctrl As Control
For Each ctrl In oForm.Controls
cReturn = ctrl
If ctrl.Name.ToString = sName Then
Return ctrl ' this is what we want!
End If
Next
Return cReturn
End Function
' Example Usage
Dim oButton As Button = GetControlByName(Me, "Button44")
If oButton.Name.ToString = "Button44" Then
MessageBox.Show("I have found your Button!")
Else
MessageBox.Show("Your button was NOT Found!")
End If
Obviously there is room for error with this function, because if sName is NOT found, then it will return the last ctrl found, therefore, you will need to ensure that the control you seek is indeed found, via the If statement as provided in the example above...
Furthermore, it may not loop through controls inside of containers, menus, etc, but I'm not sure on that, so you will need to check to ensure it's not having that problem...
(The Me in the statement will most likely be used more often than not, though Me could be the name of the form you are searching if you are running the code outside of the form you are searching the form with the function.)
FINALLY, to answer your question, you will need to change Control to Image, and Set CReturn as a New Image, and then use Return ctrl.BackgroundImage (etc) to return the image..
First, I have function to flatten all controls on a Control:
Protected Function GetAllControls(Optional ownerControl As Control = Nothing) As IEnumerable(Of Control)
Dim ret = New List(Of Control)()
For Each child As Control In If(ownerControl, Me).Controls
ret.AddRange(GetAllControls(child))
Next
ret.Add(ownerControl)
Return ret
End Function
Then, I want to hide certain buttons on a control using this code:
Dim buttons = GetAllControls().Where(Function(c) c.Name.StartsWith("subButton"))
For Each ctrl As Control In buttons
ctrl.Visible = False
Debug.WriteLine("Hid button " & ctrl.Name)
Next
Yet, after four buttons - the correct count - have been hidden, I get a NullReferenceException, with VS2012 highlighting the lambda expression.
What could possibly cause this?
The last line in your first function adds ownerControl, which is null the first time you call it, so its adding a Nothing to the list. In your lambda you're doing a c.Name which will throw an exception when c is Nothing.