How to Use VBA to Set the ControlSource Property of an Access Image Control (and Other Deeply Hidden Object Properties)

Ever wonder why you can set some values in the form/report designer Property Sheet but not in VBA? You may just need this well-hidden workaround.

How to Use VBA to Set the ControlSource Property of an Access Image Control (and Other Deeply Hidden Object Properties)

Microsoft adds properties to the Access object model more frequently than they update the object model itself.

I know that's a confusing sentence, so let me clarify it with an example.  Back in Access 2007, Access added support for a ControlSource property to the Image control.  You can see this new property on the control's Property Sheet in form/report design view:

If you try to access this property in VBA, though, it does not exist.  At least, not as a standalone property of the Image control object:

You can access this property, but only through the Image control object's .Properties collection:

Let's revisit my opening sentence now:

Microsoft adds properties to the Access object model more frequently than they update the object model itself.

In the example I used, Microsoft added a ControlSource property to the Image Control object ("Microsoft adds properties to the Access object model").  However, they did not directly expose a .ControlSource property as a standalone public member of the object (i.e., they did not "update the object model itself").  Since the .Properties collection of the Image Control object already existed, simply adding another item to that collection did not result in updating the object model itself.

While this may seem like a distinction without a difference, there's a very good reason for this approach: backwards compatibility.

Maintaining Backwards Compatibility

Changing the public interface of the Access object model has far-reaching consequences.

If Microsoft were to add a .ControlSource public property to the Image Control object, it would result in a breaking change to the object's API (application programming interface).  Not only would it break the API for that object, by extension it would break the API for the entire Access object model.

For .accdb's, I don't think this is a huge deal.  For .accde's, though, it means that any .accde compiled by a version of Access that has the new .ControlSource property, the generated .accde would fail to open in all older versions of Access that do not support the .ControlSource property...even if you never use the .ControlSource property in any of your code.

Microsoft doesn't take such breaking changes lightly, so new properties often wind up only appearing as items in the respective object's Properties collection.

Stringly-Typed Programming

This approach to adding functionality via literal strings is pejoratively known as "stringly-typed programming."

It's something you should avoid, as it tends to turn compile errors into runtime errors, which is bad.  However, there are justifications for stringly-typed programming and maintaining backwards compatibility seems to be one of the more justifiable.

That said, there have now been at least five major releases to Microsoft Access since Access 2007.  You would have thought that at some point a few of these items could have been added to the object model.

Video Demonstration

In his recent Access Europe User Group presentation, Access MVP Karl Donaubauer discussed this issue as one of his "baker's dozen" of Access tips and tricks.

Here's an excerpt from Karl's video:

Properties via VBA that do not exist in VBA
Microsoft does not want to change the VBA object model for every new Access property so as not to lose backward compatibility. Therefore, some properties do not exist with .PropertyName in VBA. However, there is a workaround. 3 Examples:

1. Image Control Source (since Access 2007)
Not like this: Me!Mylmage.ControlSource
Like this: Me!Mylmage.Properties("ControlSource")

2. Control Layout (since Access 2007)
Not like this: Me!MyControl.Layout
Like this: Me!MyControl.Properties("Layout").Value
other properties: LayoutID, RowStart, RowEnd, ColumnStart, ColumnEnd

3. Label Name (since Access 2019)
Not like this: Me!MyTextbox.LabelName
Like this: Me!MyTextbox.Properties("LabelName")

Cover image created with Microsoft Designer

All original code samples by Mike Wolfe are licensed under CC BY 4.0