Get current subform control (container) name

Taking MarkK's code we can eliminate the collection and just reference the container relevant to the subform:

Code:
Private subCont As Control

Private Sub Form_Load()
    Dim ctrl As Control
    For Each ctrl In Me.Parent.Controls
        'find the subform, and reference it
        If ctrl.ControlType = acSubform Then
            If ctrl.Form Is Me Then
                  Set subCont = ctrl
                  Exit For
            End If
        End If
    Next
End Sub
 
... then presenting the information as a Property.

IMHO, a property accessor method (Get/Let(set)) is used when the data for the property is intended to be exposed outside the class object (the principle of encapsulation). So the block beginning "Property Get Subforms() As VBA.Collection" exposes Subforms() outside of the subform object. I don't think that is actually intended or required here - it would be an odd thing to expose. For example, from the main form you can currently use Me!sfm1.Form.Subforms.Count.

So we would think, ok lets just make it private... "Private Property Get..." (it's Public by default). But under OOP the whole purpose of accessor methods Get/Let(Set) are to provided public access to properties. There's no such notion as a private property made available via an accessor method in OOP afaik (VBA breaks the rule). You already have direct access to the private variable m_sfms in any case. So applying an accessor doesn't achieve what an accessor is intended to do (encapsulate). In my view, it would be appropriate to use a private function in this case. Alternatively, create a class to encapsulate m_sfms.

I am basing my view on the wider usage of OOP and accept that VBA bends the OOP rules.
 
Very nice sum up Chris. I'm going to put a link to this from the evolving OOP thread started a few months ago. Private Properties and the calendar suggested by Markk (so you have 7 instances of the same form on the main form) -- very "classy".
 
I would expose the Public Property Get Subforms As VBA.Collection from the parent form so it is only ever built once. Putting it on the subform was just to prove it could work that way, but it belongs on the main form as a specialized controls collection. Doing that work on every subform is duplication of effort, and therefore a waste.

One HUGE advantage in VBA of using properties is that they are evaluated during debugging in the locals window, so if you expose objects as properties, private or not, and break into code, you can minutely dissect and drill down into your class structures, which I find very handy. If I write a custom class, most of its members, particularly objects, I'll expose as properties, which makes looking into that class very easy.

By way of example, you can do this with a bound form, break into code on a button click or something, open the locals window, expand the Me node, find the recordset, find the fields collection, find a field, find that field's Value property, and in doing this notice how you can drill down into the current state of the object tree. If you use classes or write classes in VBA, your properties will be visible and evaluated in this view.
 
Thank you all for this question and great replies! I have a subform used 5 times on a parent form. The subform show last month's forecast. If the forecaster wants to keep last month's forecast this month, a simple double click on the forecast number copies it to this month's forecast. Therefore, I needed to know the actual location of my subform. Is it Labor, Material, Contracts, Equipment, or Other. Once know, the subform then calculates which subform holds this month's forecast information, therefore knows where to write the forecast from last month.
Works like a charm and I really do appreciate this "leg up!"
 
Thanks for the solution MarkK it was very useful for me to read and useful code to know about.

However in this case I believe there is an easier way!

If a subform is setup on a main form, you simply create a public variable named "mode" in the subform's module. In the main form's form_open event you set the value of the variable in the subform and all the other subforms to tell it "what it is!" and how it needs to behave.

eg

me.MySubFormControlName.form.Mode = 1

Best to sue a enum instead of the "1" though.

I think this helps the subform to "encapsulate" the code better.

Here's a line form a main form that I wrote recently, which instead of using a public variable uses a sub that initialises the form and sets it up to behave the way it needs to:

Me.SFMyFormThatCanBehaveInDifferetnWays.Form.subInitialise FormMode:=MyEnum.UseQuery1


This works fine until the code crashes and variables are reset. So to make it a bit more resilient I DO NOT refer the the public variable in the other subform code, instead I use a function to get the value of the public variable.

In this way if the public variable is not set you can raise and error and ABORT!
 
The simple solution is :


Screen.ActiveForm.ActiveControl.Name

it took me three hours but...
As far as I understand the subform container is a control of the main form, meanwhile the underlying subform object is an object of the subfromcontainer.
May be I'm wrong but the expression is working like charm :-)


with best regrads :)
 
To save having to click on the subform, this code will cycle through all the controls in a form and print the names of each subform container & the actual subform object names

Code:
Dim ctrl As Control
For Each ctrl In Me.Controls
        If ctrl.ControlType = acSubform Then
            Debug.Print "Subform container name = " & ctrl.Name
            Debug.Print "Subform object name = " & ctrl.Form.Name
        End If
Next

For example:
Subform container name = subControlTypes
Subform object name = subfrmControlTypes1
 

Users who are viewing this thread

Back
Top Bottom