我有一个承载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中的代码将cellrangecellr解释为用户窗体本身中声明的局部变量。您没有在用户表单中声明这样的变量,并且您没有使用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.cellm_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

09-26 20:18
查看更多