Please don\'t consider this question as a repeated question! This question is clearly different from earlier similar-looking queries.
Can you try this. A bit rushed, so wouldn't be surprised if something goes wrong, but will come back tomorrow if so.
Behind the form
Private col As Collection
Private Sub UserForm_AddControl(ByVal Control As MSForms.Control)
Dim cl As Class2
Dim ctl As MSForms.CommandButton
Set col = New Collection
For Each ctl In Me.Controls
Set cl = New Class2
Set cl.btEvents = ctl
col.Add cl
Next ctl
End Sub
Private Sub UserForm_Initialize()
Dim btEx As MSForms.CommandButton
Set btEx = UserForm1.Controls.Add("Forms.CommandButton.1")
With btEx
.Top = 12
.Left = 12
.Width = 72
.Height = 36
.Caption = "Click Me"
End With
End Sub
Class module The only change here is to add some spacing so the buttons don't appear on top of each other.
Public WithEvents btEvents As MSForms.CommandButton
Private Sub btEvents_click()
Dim btEx As MSForms.CommandButton
Set btEx = UserForm1.Controls.Add("Forms.CommandButton.1")
With btEx
.Top = 30 * UserForm1.Controls.Count
.Left = 30
.Width = 72
.Height = 36
.Caption = "Click Me"
End With
End Sub
Implementing a collection of classes, where each class contains a button, is the key to making this work. Drawbacks to the common approach are that the class holds a reference to the UserForm, and the events are handled in the class itself. Ideally, we would like to get all the button code back into the UserForm including the handling of events.
How can this be done since Collections cannot be declared WithEvents? This can be accomplished by a global notification mechanism:
UserForm
Option Explicit
Private WithEvents MyNotifier As Notifier
Private MyControls As Collection
Private Sub UserForm_Initialize()
Set MyNotifier = GetNotifier()
Set MyControls = New Collection
AddButton
End Sub
Private Sub MyNotifier_Click()
AddButton
End Sub
Private Sub AddButton()
Dim c As MSForms.CommandButton
Set c = UserForm1.Controls.Add("Forms.CommandButton.1")
c.Width = 72
c.Height = 36
c.Top = UserForm1.Controls.Count * c.Height
c.Left = 12
c.Caption = "Click Me"
Dim mc As MyControl
Set mc = New MyControl
mc.Add c
MyControls.Add mc
End Sub
There are 3 support modules with this architecture. The first is a module that holds a global notifier. We create and access this notifier through the GetNotifier method. This method guarantees there is one and only one instance.
Module
Option Explicit
Private m_Notifier As Notifier
Public Function GetNotifier() As Notifier
If m_Notifier Is Nothing Then Set m_Notifier = New Notifier
Set GetNotifier = m_Notifier
End Function
The second is a class that defines the notifier. This singleton class is an event coordinator. It allows redirection of events, in this case from the MyControl class back to the UserControl.
Notifier Class
Option Explicit
Public Event Click()
Public Function Click()
RaiseEvent Click
End Function
The third is a class that holds the button. The response to the button click event is to call a method of our Notifier which in turn raises an event back to the UserControl:
MyControl Class
Option Explicit
Private MyNotifier As Notifier
Private WithEvents btEx As MSForms.CommandButton
Public Sub Add(ByVal c As MSForms.CommandButton)
Set MyNotifier = GetNotifier()
Set btEx = c
End Sub
Private Sub btEx_Click()
MyNotifier.Click
End Sub