I have a method where, given a VBComponent
, I can access the .Designer
and from there, the .Controls
collection:
private void DeclareControlsAsMembers(VBComponent form)
{
var designer = form.Designer;
if (designer == null)
{
return;
}
// using dynamic typing here, because not only MSForms could have a Controls collection (e.g. MS-Access forms are 'document' modules).
foreach (var control in ((dynamic)designer).Controls)
{
var declaration = new Declaration(_qualifiedName.QualifyMemberName(control.Name), ...);
OnNewDeclaration(declaration);
}
}
The problem with this method is that, when the host is MS-Access, form.Designer
is null
, so the method returns early.
The dynamic
cast here isn't particularly useful, it seems I could be casting to a UserForm
interface and it would "just work" - at least in an Excel host.
But since MS-Access' forms don't have a designer (???), how do I go about iterating controls on a MS-Access form, given C# code that's a VBE add-in (i.e. which can only easily access whatever the VBIDE API makes available)?
You can't iterate the controls on an Access form unless the form is open. Opening forms, even to design mode, is expensive, as controls need to be rendered, and being Access, the bound properties are resolved to database objects. There's also the issue of sub-forms and sub-reports.
But, this VBA code will take your vbComponent, open the form (if it isn't already open, in design mode), and then return the controls collection from the vbComponent's Properties collection. If the form wasn't open at the outset, then it is closed.
This code is fairly easy to replicate for Access Reports.