Access controls of a frame passed by reference in

2019-08-17 17:07发布

问题:

I am trying to pass many MSForms.Frames of a UserForm to a sub that is supposed to do stuff with the textboxes they contain:

initFrame(frame1)

However, once passed, I cannot access the .Controls property of that frame anymore (added a watch during debug, all that's left are Items).

I have tried many different sub declarations, but they either don't compile or lose the properties...

Private Sub initFrame(ByRef currFrame As MSForms.Frame)
Private Sub initFrame(ByRef currFrame As MSForms.Object)
Private Sub initFrame(ByRef currFrame As Frame)
Private Sub initFrame(ByRef currFrame As Object)

In all case, I get a runtime error when it gets to

For Each ctl In currFrame.Controls

Do I have to do something special to access the controls ? Like casting ?

Here is the whole code (ignore the .Name assignements):

Private Sub initTabs()
initFrame (frPrDetails)
initFrame (frPcDetails)
initFrame (frScDetails)

End Sub

Private Sub initFrame(ByRef currFrame As Frame)
Dim ctl As Control
With currFrame
    For Each ctl In .Controls
        If TypeName(ctl) = "TextBox" Then
            If ctl.TabIndex <> 57 Then
                Select Case (ctl.TabIndex) Mod 7
                    Case 1
                        'ctl.Name = "tb" & ctl.tag & "MP"
                    Case 2
                        'ctl.Name = "tb" & ctl.tag & "HW"
                    Case 3
                        'ctl.Name = "tb" & ctl.tag & "SW"
                    Case 4
                        'ctl.Name = "tb" & ctl.tag & "IC"
                    Case 5
                        'ctl.Name = "tb" & ctl.tag & "ES"
                    Case 6
                        'ctl.Name = "tb" & ctl.tag & "CONT"
                    Case 0
                        'ctl.Name = "tb" & ctl.tag & "ST"
                End Select
            Else
                'ctl.Name = "tbPrTotal"
            End If
            ctl.Text = ctl.Name
        End If
    Next ctl
End With
End Sub

回答1:

The reason is simple but very subtle.

First of all, by default, parameters are passed by reference, so :

Private Sub initFrame(currFrame As MSForms.Frame) ' ByRef is optional

But, if the parameter is an expression, then a new object/variable is created.
So believe it or not, (frame1) and frame1 are not the same thing.

Back to the issue, when you call the function, either use:

Call initFrame(frPrDetails) ' note the lack of space before the opening bracket

or simply

initFrame frPrDetails

but not initFrame (frScDetails) which is equivalent to Call initFrame((frPrDetails))