refer to name with variable in visual studio 2010 vb - vb.net

I'm trying to assign text from "comp" in the form "home" to a textbox with the name "d1" in the form "home".
but this needs to be done with a counter in the form "home".
The code is in a module.
What I've tried=
home.controls("d" & home.counter).text = home.comp.text
I keep getting an error:
use the new keyword to create an object instance ==> the textbox exists in the form
check to determine if the object is null before calling the method ==> the textbox is empty
get general help for this exception

You could use Controls.Find:
Dim controls = home.Controls.Find("d" & home.counter, True)
If controls.Length > 0 Then
Dim txt = TryCast(controls(0), TextBoxBase)
If txt IsNot Nothing Then
txt.Text = home.comp.text
End If
End If
However, normally i would not use this approach since it's error-prone. Why don't you provide a public property in the Home-form that you can access? This property would get/set the TextBox' Text.
For example:
Public Property HomeCompText As String
Get
Return txtHomeComp.Text
End Get
Set(value As String)
txtHomeComp.Text = value
End Set
End Property
Now you can use this clear, safe and maintainable code:
home.HomeCompText = home.comp.text
You could even change the underlying control.

Related

How can I get the checkbox.checked event to fire when I pass it as a parameter in vb.net?

I have programmed a long time but I’m relatively new to vb.net. And I’ve avoided subroutines and functions in which I passed parameters because I always get stuck. I’m trying to write a subroutine to pass information that will fill a TextBox or a checkbox with either the value from a table or clear the field or set to false. The first code below is an example of what I’ve been doing and this works. I trying to write a subroutine to pass 1.the name of the textbox or checkbox control on my form,2.the data row value, and 3.the column name in the table. The problem is when I passed a checkbox I can’t get the checked event to show on my control(CoreCol) that I passed. It knows it’s a checkbox and it will set the text of the checkbox too true or false but it won’t change the box checked.
This is an example of the old way that works. For a TextBox and a checkbox
' A Machine
If Not IsDBNull(r("A Machine")) Or Not IsNothing(r("A Machine")) Then
TbXMachA.Text = r("A Machine")
Else
TbXMachA.Text = ""
End If
If Not IsDBNull(r("A CO2 Box?")) Or Not IsNothing(r("A CO2 Box?")) Then
CkbxCO2BoxA.Checked = r("A CO2 Box?")
Else
CkbxCO2BoxA.Checked = False
End If
This works
LoadData2TextBox(Me. TbXMachA, r, "A Machine ")
This doesn’t
LoadData2TextBox(Me.CkbxCO2BoxA, r, "A CO2 Box?")
this is the sub routine I'm writing
Private Sub LoadData2TextBox(ByRef CoreCol As Control, CoreRow As DataRow, BoxStage As String)
If Not IsDBNull(CoreRow(BoxStage)) Then
If TypeOf CoreCol Is TextBox Then
CoreCol.Text = CoreRow(BoxStage)
End If
If TypeOf CoreCol Is CheckBox Then
CoreCol.??? = CoreRow(BoxStage)
End If
Else
CoreCol.Text = ""
End If
You know that CoreCol is a CheckBox so you can cast it as one then use it as a CheckBox.
If TypeOf CoreCol Is CheckBox Then
Dim myCheckBox = DirectCast(CoreCol, CheckBox)
myCheckBox.Checked = DirectCast(CoreRow(BoxStage), Boolean)
End If
Another cast in getting the boolean value out of CoreRow(BoxStage). The above code assumes this will work, but I am not sure what is in CoreRow(BoxStage). You may need to add some logic based on the value depending on what it is. For example:
myCheckBox.Checked = CoreRow(BoxStage) = "somevalue"

Access VBA - How to get the properties of a parent subform, or, get the user-given name for a subform (not the object reference name)

In MS Access 2016, let's say I have 2 forms: frmMain and frmBaby.
I have embedded frmBaby as a subform on frmMain. I have embedded on frmBaby a control (let's say it's a textbox, but it could be any control) named tbxInput.
On frmMain, since frmBaby is a "control" on frmMain, I have given that control the traditional name of subfrmBaby.
Now, in VBA, an event on subfrmBaby passes the tbxInput control ByRef (as Me.tbxInput) to a function that is meant to return the .Left property of the parent of the control passed ByRef. That is, I need the function to determine the .Left property for the location of subfrmBaby on frmMain. (The function is more complicated than this, but for the sake of keeping this question let's just say the function is returning the .Left property value because the .Left value is what I need to perform the function.)
Let's say the function is: Public Function fncLocation(ByRef whtControl As Variant) as Long
(I use Variant so that null values can be passed.)
Here is the code that I expected to return the .Left value of the parent (i.e., subfrmBaby) of whtControl: lngLeft = whtControl.Parent.Left
However, that gives me an error of: "Application or object-defined error"
When I use the immediate window to check things out I find that whtControl.Parent.Name is "frmBaby" and not "subfrmBaby" which makes it problematic to reference the subform on frmMain since I cannot figure out how to get the actual name given to the control on frmMain from the object passed to the function and so I cannot reference the subform by name either.
Questions:
How can I get the .Left value for the parent of the control passed to this function?
How can I get the actual name assigned to the subform control on frmMain? In this case, I need the name of "subfrmBaby" rather than "frmBaby."
Thanks in advance for ideas.
You can do this by iterating the controls on the main form, assuming whtControl is the form object of the subform (if it's a textbox, it's whtControl.Parent.Parent and If c.Form Is whtControl.Parent Then)
Dim mainForm As Form
Set mainForm = whtControl.Parent
Dim c As Access.Control
Dim subformControl As Access.Control
For Each c In mainForm.Controls
If TypeOf c Is SubForm Then
If c.Form Is whtControl Then
Set subformControl = c
Exit For
End If
End If
Next
If Not subformControl Is Nothing Then
Debug.Print subformControl.Left
End If
Note that iterating controls comes at a performance penalty, but this code should still take milliseconds, not seconds. Also, since we test reference equality, it works even if the same subform is present multiple times on the parent form.
I just had this issue, and I think I solved it! Thanks to Eric A's answer above to get me started. I tweaked it and built on it for my use. In my case, I needed to save the "full" address of a control to build and facilitate a control log (used to log both user actions for auditing and to allow for users to "undo" an action). I have several duplicated subforms in several sub-form controls, and a few sub-sub forms (each displaying differently filtered and sorted data), so I couldn't rely on simply knowing the subform's name, I also needed the subform control name. This also leverages others' work (as noted in the code notes with some tweaks to allow easier re-use for us. I've posted it here, hopefully it will help someone else. I know I've used SO a lot.
How we use it:
On a form, after logging an action, we record the control's ID info, which calls a function to get the toppost form (this is used in conjunction with afterUpdate event so we refresh the main form and subform). We also use the HWND to validate some other items elsewhere, and to grab a form if we don't have the initial form reference. If you use this and modify it, please point back to here and give comments.
Specific Function Code to get Control "address" and get control from address
' Posted on StackOverflow 2022 February 18 in response to Question:
' https://stackoverflow.com/q/66425195/16107370
' Link to specific answer: https://stackoverflow.com/a/71176443/16107370
' Use is granted for reuse, modification, and sharing with others
' so long as reference to the original source is maintained and you
' help lift others up as others have done those who helped with this concept
' and code.
Private Function GetControlAddress(ByRef ControlTarget As Object, _
ByRef ParentForm As Access.Form) As String
' Used in concert with building a form ID, this allows reflection back to the specific
' subform control and containing subform.
Dim ControlSeek As Access.Control
If TypeOf ControlTarget Is Form Then
' You need to dig through the whole list to get the specific controls for proper reflection down.
For Each ControlSeek In ParentForm.Controls
If ControlSeek Is ControlTarget Then
GetControlAddress = ParentForm.Name & FormIDHWNDSep & ParentForm.Hwnd & FormIDHWNDSep & ControlTarget.Name & FormIDFormSep
Exit For
ElseIf TypeOf ControlSeek Is SubForm Then
If ControlSeek.Form Is ControlTarget Then
GetControlAddress = ParentForm.Name & FormIDHWNDSep & ParentForm.Hwnd & FormIDHWNDSep & ControlSeek.Name & FormIDFormSep
End If
End If
Next ControlSeek
Else
' If you're not looking for a form, then you can skip the slow step of running through all controls.
GetControlAddress = ParentForm.Name & FormIDHWNDSep & ParentForm.Hwnd & FormIDHWNDSep & ControlTarget.Name & FormIDFormSep
End If
End Function
Public Function GetControlByAddress(ByRef StartingForm As Access.Form, ByRef strControlAddress As String) As Access.Control
' Given a control address and a starting form, this will return that control's form.
Dim ControlTarget As Access.Control
Dim TargetForm As Access.Form ' This is a reference to the hosting control
'Dim ControlSeek As
Dim FormIDArr() As String
Dim FormInfo() As String
Dim ControlDepth As Long
Dim CurrentDepth As Long
If strControlAddress = vbNullString Then GoTo Exit_Here
FormIDArr = Split(strControlAddress, FormIDFormSep)
' Because there's always a trailing closing mark (easier to handle buidling address), we skip the last array
' value, as it's always (or supposed to be...) empty.
ControlDepth = UBound(FormIDArr) - LBound(FormIDArr)
' Split out the form's Specific Information to use the details.
FormInfo = Split(FormIDArr(CurrentDepth), FormIDHWNDSep)
' The specific control is located in the 3rd element, zero referenced, so 2.
Set ControlTarget = StartingForm.Controls(FormInfo(2))
' If ControlDepth is 1 (control is on passed form) you can skip the hard and slow work of digging.
If ControlDepth > 1 Then
For CurrentDepth = 1 To ControlDepth - 1
' Note: you start at 1 because you already did the first one above.
' Split out the form's Specific Information to use the details.
FormInfo = Split(FormIDArr(CurrentDepth), FormIDHWNDSep)
Set TargetForm = ControlTarget.Form
Set ControlTarget = TargetForm.Controls(FormInfo(2))
Next CurrentDepth
End If
Exit_Here:
Set GetControlByAddress = ControlTarget
End Function
Required Helper Functions
Note, I use a property for the separators as there is some user locale handling (no included), and it also ensures that if we do change the separator it remains consistent. In this example, I simply set them to a character which is unlikely to be used in a form name. You will need to ensure your forms don't use the separator characters.
Public Function hasParent(ByRef p_form As Form) As Boolean
' Borrowed concept from https://nolongerset.com/get-top-form-by-control/
' and modified for our uses.
On Error Resume Next
hasParent = (Not p_form.Parent Is Nothing)
Err.Clear ' The last line of this will cause an error. Clear it so it goes away.
End Function
Private Function GetFormObjectByCtl(ByRef ctl As Object, _
ByRef ReturnTopForm As Boolean, Optional ByRef strControlAddress As String) As Form
strControlAddress = GetControlAddress(ctl, ctl.Parent) & strControlAddress
If TypeOf ctl.Parent Is Form Then
If ReturnTopForm Then
If hasParent(ctl.Parent) Then
'Recursively call the function if this is a subform
' and we need the top form
Set GetFormObjectByCtl = GetFormObjectByCtl( _
ctl.Parent, ReturnTopForm, strControlAddress)
Exit Function
End If
End If
Set GetFormObjectByCtl = ctl.Parent
Else
'Recursively call the function until we reach the form
Set GetFormObjectByCtl = GetFormObjectByCtl( _
ctl.Parent, ReturnTopForm, strControlAddress)
End If
End Function
Public Function GetFormByCtl(ctl As Object, Optional ByRef strControlAddress As String) As Form
Set GetFormByCtl = GetFormObjectByCtl(ctl, False, strControlAddress)
End Function
Public Function GetTopFormByCtl(ctl As Object, Optional ByRef strControlAddress As String) As Form
Set GetTopFormByCtl = GetFormObjectByCtl(ctl, True, strControlAddress)
End Function
Public Property Get FormIDHWNDSep() As String
FormIDHWNDSep = "|"
End Property
Public Property Get FormIDFormSep() As String
FormIDFormSep = ";"
End Property
Interesting. I don't think you can.
As you have seen, the parent of whtControl is its form, frmBaby.
The parent of that one is frmMain. The subform control is not part of the object chain when "going up", only when going down.
If you always use the naming scheme as in the question, you could do something like this (air code):
strSubform = whtControl.Parent.Name
strSubformCtrl = "sub" & strSubform
Set ctlSubform = whtControl.Parent.Parent(strSubformCtrl)

How to show property of a UserControl in Properties panel

I created a UserControl in VB.NET. I used following code to set some text to a TextBox via code, it works when I refer to it via code, but the issue is it doesn't show up in Properties window.
Dim text1_text As String = Nothing
<
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Category("Appearance"),
Description("The text to be shown in textbox"),
Browsable(True),
EditorBrowsable(EditorBrowsableState.Always)
>
Property Text1 As String
Get
Return text1_text
End Get
Set
text1_text = Value
TextBox1.Text = Value
End Set
End Property

How do I select specific variables based on checkbox state as I iterate through a For Each

I'm working on a project that requires I iterate through a list of controls on a tabpage to find all of the checkboxes. Then depending on the state of the box (checked or unchecked) select individual variables (filenames) to then perform either a batch rename or delete of files on the filesystem (cb.checked = perform action).
I have managed to create the "for each" for the iteration of the controls (thanks google) but I'm struggling to figure out how to pick the variables. They are all named differently, obviously, as are the checkboxes. Also the checkboxes are statically assigned to the form/tabpage. Here's what I have at the moment.
Public Sub delBut_code(ByRef fname As String)
If (Sanity = 1) Then
For Each cb As Control In Form1.Controls
If TypeOf cb Is CheckBox AndAlso DirectCast(cb,
CheckBox).Checked Then
If My.Computer.FileSystem.FileExists(fname) Then
My.Computer.FileSystem.DeleteFile(fname)
End If
End If
Next
MessageBox.Show("All Actions Completed Successfully")
Else
MessageBox.Show("Please select a File To Delete")
End If
End Sub
and here is an example of some of the variables:
Dim castle As String = selPath & "\zm_castle_loadingmovie.txt"
Dim factory As String = selPath &
"\zm_factory_load_factoryloadingmovie.txt"
Dim island As String = selPath & "\zm_island_loadingmovie.txt"
N.B selpath collects a user entered folder path and can be ignored here
I would really appreciate any pointers.
First, you can do much better with the loop:
Public Sub delBut_code(ByRef fname As String)
If Sanity <> 1 Then
MessageBox.Show("Please select a File To Delete")
Exit Sub
End If
Dim checked = Form1.Controls.OfType(Of CheckBox)().Where(Function(c) c.Checked)
For Each box As CheckBox in checked
Try
'A file not existing is only one reason among many this could fail,
' so it needs to be in a Try/Catch block.
' And once you're using a Try/Catch block anyway,
' the FileExists() check becomes a slow and unnecessary extra trip to the disk.
My.Computer.FileSystem.DeleteFile(fname)
Catch
'Do something here to let the user know it failed for this file
End Try
Next
MessageBox.Show("All Actions Completed")
End Sub
But now you need to know how have the right value in that fname variable. There's not enough information in the question for us to fully answer this, but we can give some suggestions. There a number of ways you could do this:
Set the Tag property in the Checkboxes when you build the string variables. Then fname becomes DirectCast(box.Tag, String).
Inherit a custom control from CheckBox to use instead of a normal Checkbox that has an additional String property for the file name. Set this property when you build the string variables.
Name your string variables in a way that you can derive the string variable name from the CheckBox variable name, and then use a Switch to pick the right string variable from each box.Name.
Keep a Dictionary(Of CheckBox, String) that maps the Checkboxes to the right string values.
But without knowing more context of the application, I hesitate to recommend any of these over the others as best for your situation.

Convert Control Using Cast Not Working

i have a control named SuperValidator1 on every form with SuperValidator type. i want to find this control and enable it using its name because the name is consistent in all forms. so this is the code i came up with :
Dim validator As SuperValidator
Dim frm As Form = Me.ParentForm
Dim ctrl As Control()
ctrl = frm.Controls.Find("SuperValidator1", True)
Dim singleCtrl As Control = ctrl(0)
validator = TryCast(singleCtrl, SuperValidator) '< ERROR LINE
it throws editor error : Value of Type 'Control' cannot be converted to 'SuperValidator'
i tried CType and DirectCast but it is the same. according to this i should be able to cast any data type. what is wrong and what should i do ?
btw SuperValidator is from DevComponents.DotNetBar.Validator
thanks
Since SuperValidator is a component you must get it from your form's component collection. However at runtime components don't seem to inherit a name, so finding the exact one might be tricky.
As far as I know your only options are:
A) Get the first SuperValidator you can find, or
B) Match its properties (if possible).
Either way you do it you must iterate through the Me.components.Components collection:
Dim validator As SuperValidator = Nothing
For Each component In Me.components.Components
If component.GetType() Is GetType(SuperValidator) Then
validator = DirectCast(component, SuperValidator)
'Perform additional property checking here if you go with Option B.
End If
Next
Here is a test that uses a control I have on a form. Changed your logic slightly. Give it s try and see what results you have.
Dim validator As RichTextBox ' SuperValidator
Dim frm As Form = Me ' .ParentForm
Dim ctrl() As Control = frm.Controls.Find("RichTextBox1", True) ' ("SuperValidator1", True)
If ctrl.Length > 0 Then
validator = TryCast(ctrl(0), RichTextBox) ' , SuperValidator) < ERROR LINE
Else
Stop
End If