In my article, Using WithEvents to Encapsulate Event Handling Code, I took a bit of a shortcut to find the form object from a text box control. In that situation, we were dealing with text boxes in the detail section of a continuous form. And in almost all cases, the parent of such a text box control will be the form itself.
However, I did offer the following caveat in that article:
(* NOTE: There are some corner cases where the control's parent is something other than the containing form object, but we're going to set those aside to keep this article focused on the task at hand.)
Let's properly handle those corner cases now.
Every control in Access has a Parent property. Different types of controls can have different types of parents.
Let's consider a highly contrived example:
- Create a form named MyForm
- Add a tab control named MyTabCtl
- On Page1 of the tab control, add an option group named MyOptionGroup
- Inside the option group, add an option named MyOption
- Rename the option's label to MyLabel
Now, let's write a routine to show the ancestry of the innermost control, MyLabel:
Sub ShowParents() Dim Lbl As Label Set Lbl = Form_MyForm.MyLabel Debug.Print Lbl.Parent.Name Debug.Print Lbl.Parent.Parent.Name Debug.Print Lbl.Parent.Parent.Parent.Name Debug.Print Lbl.Parent.Parent.Parent.Parent.Name Debug.Print Lbl.Parent.Parent.Parent.Parent.Parent.Name End Sub
Here's the output if we run the routine in the Immediate Window:
Finding the Form
As the above code shows, it's naive and dangerous to assume that the parent of any given control is the form. However, being able to reliably return the enclosing form of an arbitrary control could prove handy. And with a couple neat tricks–namely, recursion and TypeOf...Is expressions–it's not even all that hard. Heck, if you're a weirdo like me, you might even say it's fun.
The Code: GetFormByCtl()
The code is simple and straightforward. We check to see if the parent of the passed control is a form object. If it is, we return it. If not, we check that control's parent. Et cetera, et cetera, until we reach the form object.
'Returns the first form parent of the given control Function GetFormByCtl(Ctl As Control) As Form If TypeOf Ctl.Parent Is Form Then Set GetFormByCtl = Ctl.Parent Else 'Recursively call the function until we reach the form Set GetFormByCtl = GetFormByCtl(Ctl.Parent) End If End Function
Here's the function in action:
This particular function will return the first ancestor form object. In other words, if the control you pass to the function is on a subform, then the function will return the subform and not the top-level form.
What if you want the top-level form? I'll cover that in another article.