我有一个承载worksheet_change子类的类模块,在该子类中必须弹出一个用户窗体。我想在Userform的代码中使用来自类模块的许多变量。但是,无论我做什么,都无法正常工作。
我尝试从this very lenghty guide应用该方法,但无济于事。 SO上的其他线程无法帮助我。
Private cell As Range
Public WithEvents m_wb As Workbook
Property Get cellr() As Range
Set cellr = cell
End Property
Property Set cellr(cellrange As Range)
Set cell = cellrange
End Property
Public Property Set Workbook(wb As Workbook)
Set m_wb = wb
End Property
Public Property Get Workbook() As Workbook
Set Workbook = m_wb
End Property
Public Sub m_wb_SheetChange(ByVal Sh As Object, ByVal Target As Range) 'simplified, but accurate
Application.EnableEvents = False
For each cell in Target
ReplaceTask.Show
Next cell
Application.EnableEvents = True
End Sub
在
userform_initialize
宏中,我需要能够获取m_wb
工作簿的名称以及range
循环中的单元格(最好是For each cell in Target
变量,否则只是地址)。对于下面代码中的每个变量,我得到需要错误“ 424”对象
这表明变量不是公共的。
Private Sub UserForm_Initialize()
Debug.Print cellrange.Address
Debug.Print cell.Address
Debug.Print cellr.Address
Debug.Print m_wb.Name
'....
我很肯定,是我无法理解这些属性的工作原理,这使我感到沮丧。如果有人可以对我做错的事情有所了解,请!
最佳答案
用户窗体和带有事件处理程序的类是两个不同的作用域。您不能期望能够在不限定该范围的情况下引用其他范围的成员。 UserForm_Initialize
中的代码将cellrange
和cellr
解释为用户窗体本身中声明的局部变量。您没有在用户表单中声明这样的变量,并且您没有使用Option Explicit
,因此,当代码隐式地假设它是从未初始化的Dim cellrange As Variant
时,您将得到运行时错误424,而不是编译时错误。因此为Empty
。
若要解决此问题,您需要告诉用户实例应从中获取事件处理类的哪个实例的属性。为此,将其放在UserForm中就足够了:
Private m_ParentClass As ThatClassThatCreatesForms
Friend Sub Init(ByVal p As ThatClassThatCreatesForms)
Set m_ParentClass = p
End Sub
并将父类中的
For Each
循环更改为:For each cell in Target
ReplaceTask.Init Me
ReplaceTask.Show
Next cell
您必须具有单独的“ Init”方法,因为VBA类不能具有带参数的构造函数。
然后,
ReplaceTask
中的代码可以使用m_ParentClass.cell
,m_ParentClass.Workbook
等。但是您不能从UserForm_Initialize
执行此操作,因为尚未调用Init
。但这不是问题,只需将代码从UserForm_Initialize
移到Init
。为了更进一步,我建议您停止使用implicit form instance。手动创建实例是一个好习惯:
For each cell in Target
Dim f As ReplaceTask
Set f = New ReplaceTask
f.Init Me
f.Show
Next cell