Dim Form as as specific Form with if-statement - vb.net

I have a Sub, which works for two different Forms. When I call the Sub from one of those forms I give the Form to the Sub as a parameter.
How can I set the correct for as a variable in the Sub?
Here are two ways I have tried this, but they do not work.
Shared Sub SetDataGridViewg(ByRef Form As Form, AusAuftrag As Boolean)
' ERROR: A common type can not be derived, and Option Strict On does not allow the assumption of the Object type.
Dim AdressenÜbersicht = If(AusAuftrag, CType(Form, AdressenÜbersichtAusAuftrag), CType(Form, Startseite))
' ERROR: The variable "AdressenÜbersicht" hides a variable in an enclosing block.
If AusAuftrag Then
Dim AdressenÜbersicht As AdressenÜbersichtAusAuftrag = CType(Form, AdressenÜbersichtAusAuftrag)
Else
Dim AdressenÜbersicht As Startseite = CType(Form, Startseite)
End If
' ...
End Sub

Related

Trying to use a variable in a Set statement

I have an array oNam of TextBox names, I want to call a sub and pass an index number pointing to the specific TextBox I am working on to the sub. In the sub I use the following code, Dim MyControl As Control, and Set MyControl = Me![oNam(n)]. I get the following
Run-time error 2147024809: Could not find the specified object.
However, if I replace oNam(n) with the actual TextBox name, Me![tbxBuyNowPrice], I don't get the error. I included a Debug.Print oNam(n) and it holds the correct name.
I've replaced the variable with the actual name and it works.
Dim oNam() As Variant
....Call TextBoxControl(34)
Sub TextBoxControl(n As Integer)
Debug.Print oNam(n) <====Shows correct name
Set MyControl = Me![oNam(n)] <====GET THE ERROR HERE
If DVAL(n) = "Yes" Then
Call TextBoxSettings(MyControl, "", vbYellow)
MyControl.SetFocus
GoTo EndOfTextBoxControl
Else
Call TextBoxSettings(MyControl, 0, vbCyan)
End If
EndOfTextBoxControl:
End Sub

Word VBA Userform, Getting Control Object By Name fails sometimes

I have a userform “myUserForm” with dozens of controls whose TypeName() is “CheckBox”. I just hate having dozens of _Click() routines named like “Private Sub Chk1_Click()”, so in order to manage the quantity of _Click() routines, I simplified and made them nearly identical:
Private Sub Chk1_Click()
ProcessClickFor ("Chk1")
End Sub
Private Sub Chk2_A_Click()
ProcessClickFor ("Chk2_A")
End Sub
Private Sub Chk3_Z_Click()
ProcessClickFor ("Chk3_Z")
End Sub
ProcessClickFor() does most of the work.
Sub ProcessClickFor(anyCheckBox As String)
Dim cbControl As Object
Set cbControl = ControlByName(anyCheckBox)
If cbControl.Value Then
cbControl.Value = True
End If
End Sub
Later, when I want to work with any control, I can get the Control object by name, like:
Dim aControl As Object
Set aControl = ControlByName(“Chk3”)
MsgBox “The control named “ & cbControl.Name & “ is “ & cbControl.Visible
Function ControlByName(sName) As Object
Dim objectified As Object
For Each objectified In myUserForm.Controls
If objectified.Name = sName Then
Set ControlByName = objectified
Exit Function
End If
Next objectified
End Function
This works fine, almost, but it FAILS on the same four controls on myUserForm every time.
The failure “mode” is that ControlByName() seems to return successfully, but the first use of the returned control (such as my MsgBox) gives the error:
"Run-time error '91': Object variable or With block variable not set".
I verified that the spelling of the defined control names matches the names in my _Click() routines. Dozens of similarly designed CheckBox controls work perfectly. Could it have to do with the length of the CheckBox names or the number of “_” characters in the CheckBox names? Could there be a corrupt character in a CheckBox name? Can you think of other things for me to try?

check if textbox exists vba (using name)

I am using Ms-Access and I created a userform which has a number of Textboxes on it. The boxes are named: Box1, Box2, Box3 ...
I need to loop through all boxes, but I don't know which is the last one. To avoid looping through all userform controls I thought of trying the following:
For i =1 To 20
If Me.Controls("Box" & i).value = MyCondition Then
'do stuff
End If
Next i
This errors at Box6, which is the first box not found. Is there a way to capture this error and exit the loop when it happens.
I know I could use On Error but I 'd rather capture this specific instance with code instead.
Thanks,
George
A Controls collection is a simplified collection of controls (obviously) and share a same order as a placement order of controls.
First of all, even a creatable collection object lacks methods such as Exists or Contains , hence you need a function with error handling to checking/pulling widget from a collection.
Public Function ExistsWidget(ByVal Name As String) As Boolean
On Error Resume Next
ExistsWidget = Not Me.Controls(Name) Is Nothing
On Error GoTo 0
End Function
If you really doesnt like "ask forgiveness not permission" option you can pull entire ordered collection of your textboxes (and/or check existance by name in another loop with similar logic).
Public Function PullBoxes() As Collection
Dim Control As MSForms.Control
Set PullBoxes = New Collection
For Each Control In Me.Controls
If TypeOf Control Is MSForms.TextBox And _
Left(Control.Name, 3) = "Box" Then
Call PullBoxes.Add(Control)
End If
Next
End Function
Since names of widgets are unique - you can return a Dictionary from that function with (Control.Name, Control) pairs inside and able to check existance of widget by name properly w/o an error suppression.
There's a good guide to Dictionary if it's a new information for you.
Anyway, no matter what object you choose, if user (or code) is unable to create more of thoose textboxes - you can convert this Function above to a Static Property Get or just to a Property Get with Static collection inside, so you iterate over all controls only once (e.g. on UserForm_Initialize event)!
Public Property Get Boxes() As Collection
Static PreservedBoxes As Collection
'There's no loop, but call to PullBoxes to reduce duplicate code in answer
If PreservedBoxes Is Nothing Then _
Set PreservedBoxes = PullBoxes
Set Boxes = PreservedBoxes
End Property
After all, the last created TextBox with name Box* will be:
Public Function LastCreatedBox() As MSForms.TextBox
Dim Boxes As Collection
Set Boxes = PullBoxes
With Boxes
If .Count <> 0 Then _
Set LastCreatedBox = Boxes(.Count)
End With
End Function
I think that now things are clearer to you! Cheers!
Note: All code are definitely a bunch of methods/properties of your form, hence all stuff should be placed inside of form module.
Long story short - you cannot do what you want with VBA.
However, there is a good way to go around it - make a boolean formula, that checks whether the object exists, using the On Error. Thus, your code will not be spoiled with it.
Function ControlExists(ControlName As String, FormCheck As Form) As Boolean
Dim strTest As String
On Error Resume Next
strTest = FormCheck(ControlName).Name
ControlExists = (Err.Number = 0)
End Function
Taken from here:http://www.tek-tips.com/viewthread.cfm?qid=1029435
To see the whole code working, check it like this:
Option Explicit
Sub TestMe()
Dim i As Long
For i = 1 To 20
If fnBlnExists("Label" & i, UserForm1) Then
Debug.Print UserForm1.Controls(CStr("Label" & i)).Name & " EXISTS"
Else
Debug.Print "Does Not exist!"
End If
Next i
End Sub
Public Function fnBlnExists(ControlName As String, ByRef FormCheck As UserForm) As Boolean
Dim strTest As String
On Error Resume Next
strTest = FormCheck(ControlName).Name
fnBlnExists = (Err.Number = 0)
End Function
I would suggest testing the existence in another procedure per below: -
Private Sub Command1_Click()
Dim i As Long
i = 1
Do Until Not BoxExists(i)
If Me.Conrtols("Box" & i).Value = MyCondition Then
'Do stuff
End If
i = i + 1
Next
End Sub
Private Function BoxExists(ByVal LngID As Long) As Boolean
Dim Ctrl As Control
On Error GoTo ErrorHandle
Set Ctrl = Me.Controls("BoX" & LngID)
Set Ctrl = Nothing
BoxExists = True
Exit Function
ErrorHandle:
Err.Clear
End Function
In the above, BoxExists only returns true if the box does exists.
You have taken an incorrect approach here.
If you want to limit the loop, you can loop only in the section your controls reside e.g. Detail. You can use the ControlType property to limit controls to TextBox.
Dim ctl As Control
For Each ctl In Me.Detail.Controls
If ctl.ControlType = acTextBox Then
If ctl.Value = MyCondition Then
'do stuff
End If
End If
Next ctl
I believe the loop will be faster than checking if the control name exists through a helper function and an On Error Resume Next.
But this only a personal opinion.

VBA - OptionButton Collection

I'm trying to get a collection of option buttons. I would like the objects of my collection to have the "OptionButton" type. Is there a way to do that ?
Private Sub SetInputs()
Dim OptionButtons As Collection
Set OptionButtons = New Collection
OptionButtons.Add (br_FKG1)
' MsgBox (TypeName(br_FKG1)) : OptionButton
' MsgBox (TypeName(OptionButtons.Item(1))) : Boolean
(...)
End Sub
Thanks,
Got it. If anybody has the same problem some day, just write
OptionButtons.Add br_FKG1
without the parentheses so that the object and not the value is added.
Without parentheses, it is actually the default property of the class that is added. For an OptionButton, it is .Value, but it may be something else for other classes.

Forcing the unloading forms from memory

I am writing a solution in Excel that uses a number of linked data entry forms. To move between he sequence of forms, the user can click a "Previous" or "Next button. The current form is unloaded and the new one loaded and opened.
Sub NextForm(curForm As MSForms.UserForm, strFormName As String)
Dim intCurPos As Integer
Dim strNewForm As String
Dim newForm As Object
intCurPos = WorksheetFunction.Match(strFormName, Range("SYS.formlist"), 0)
If intCurPos = WorksheetFunction.CountA(Range("SYS.formlist")) Then
Debug.Print "No"
Else
Unload curForm
strNewForm = WorksheetFunction.Index(Range("SYS.formlist"), intCurPos + 1)
Set newForm = VBA.UserForms.Add(strNewForm)
newForm.Show
End Sub
The code as is allows new forms to be added into the sequence at any time through the editing of the range "SYS.formlist".
One problem I have noticed is that even after the current form is unloaded, it still remains in the VBA.Userforms collection. I would presume this is because this code has been called from that userform.
Is there a way to force the removal of that form from the VBA.Userforms collection? What is occuring is that if the user moves forward and then back, two copies of the form appear in memory and and excel throws exceptions about two modal forms being open.
Cheers,
Nick
The answer was (sadly) quite simple and inspired by bugtussle's answer.
The subroutine was passing the curForm variable as an MSForms.Userform object, but the form is held in memory as its own object type. (As an example, you can access a form through Set form = new formName)
So by changing the curForm paramater type to Variant, it will pass the actual object through rather than a copy of the object. Unload was only unloading the copy, not the actual object.
Thanks bugtussle!
So, corrected code is:
Sub NextForm(curForm As Variant, strFormName As String)
Dim intCurPos As Integer
Dim strNewForm As String
Dim newForm As Object
intCurPos = WorksheetFunction.Match(strFormName, Range("SYS.formlist"), 0)
If intCurPos = WorksheetFunction.CountA(Range("SYS.formlist")) Then
Debug.Print "No"
Else
Unload curForm
strNewForm = WorksheetFunction.Index(Range("SYS.formlist"), intCurPos + 1)
Set newForm = VBA.UserForms.Add(strNewForm)
newForm.Show
End Sub
I'm thinking that unloading from the collection object instead of the variable will really get rid of it. Try something like this:
For i = VBA.UserForms.Count - 1 To 0 Step -1
if VBA.UserForms(i).Name = curForm.name
Unload VBA.UserForms(i)
end if
Next i