Vba Userform会根据条件使Excel崩溃

Vba Userform会根据条件使Excel崩溃,vba,excel,userform,Vba,Excel,Userform,我正面临一个有趣的问题,我不明白 在VBA中,我希望在用户双击单元格时加载Userform,具体取决于单元格内容。但是,根据我询问的条件,一旦我退出Sub,Excel就会崩溃(即使在UserForm关闭之后,它也会继续执行代码) 这项工作: Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean) Dim myForm As New U

我正面临一个有趣的问题,我不明白

在VBA中,我希望在用户双击单元格时加载Userform,具体取决于单元格内容。但是,根据我询问的条件,一旦我退出Sub,Excel就会崩溃(即使在UserForm关闭之后,它也会继续执行代码)

这项工作:

Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
    Dim myForm As New UserForm1
    If Target.Cells(1).Value = "" Then
        myForm.Show
    End If
    Debug.Print ("OK")
End Sub
这三个因素使Excel崩溃:

一,

三,


我正在使用一个空的UserForm进行测试

尝试更改If块中的代码,以便它执行一个
Cancel=True
来忽略双击操作并预先加载表单,如下所示:

If Target.Cells(1).Value = "Test" Then
    Cancel = True
    Load myForm
    myForm.Show
End If
这似乎是一个很好的方法来限制可能出错的事情的数量

不过还有更多

Dim myForm As New UserForm1
这是在本地范围内创建一个自动实例化的
UserForm1
对象。由于
Dim
语句不可执行,这意味着无论
是否显示表单,只要输入过程范围,就会创建对象

使用
With
块,可以轻松避免无条件创建该对象,甚至可以避免为其声明变量:

Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
    If Target.Cells(1).Value = "Test" Then
        Cancel = True
        With New UserForm1
            .Show
        End With
    End If
    Debug.Print "OK"
End Sub
这样,表单实例只有在需要时才会被创建。避免了默认实例陷阱,这是一个巨大的荣誉——你可以阅读更多关于这方面的内容

注意,我还删除了
Debug.Print
参数列表周围的多余括号。括号在过程调用中实际上是有害的;当您将编译错误与多参数过程一起使用时,您将遇到编译错误;当您需要传递对象引用时,您将遇到运行时错误;当您打算传递参数时,您将遇到逻辑错误,不管被调用的过程是否表示它使用了
ByRef
参数


调用函数并在局部变量中捕获其返回值时,请使用括号。

Load myForm
将是多余的,因为
myForm
是一个对象变量,在那个时候自动实例化…我不确定这会在OP的计算机上产生什么影响,但没有其他两个人测试相同的代码?我不知道我可以直接在With块中实例化和创建对象。从现在起,如果适用,我将尝试使用此选项。感谢您提供有关使用括号的详细信息。@Svatik或者,您可以通过将局部变量
Dim myForm声明为UserForm1
,然后在条件块内执行
Set myForm=New UserForm1
来分离
Dim
New
。尽管如此,我喜欢使用New
保存对象实例并确保其正确销毁的方式(永远不要跳入/跳出带有New块的
),至于
作为New
的含义,尝试使用New UserForm1执行
Dim foo,然后执行
设置foo=Nothing
,然后,
Debug.Print foo什么都不是
-比较期望值和实际值;-)我不确定是否理解最后一部分。这是否意味着即使我对物体没有任何影响,它也不会被摧毁?或者,当我在Debug.Print中使用它时,它是否再次实例化?当您将
Dim foo作为新事物
时,VBA确保
foo
在其声明的整个范围内都是
事物
的有效实例,无论发生什么情况。在
UserForm
的情况下,这可能意味着用户单击红色的“X”关闭表单,对象与其状态一起被销毁(假设您没有处理
QueryClose
),然后当调用代码查询表单的状态(例如某些属性或复选框状态)时,它读取的是默认状态,因为它不是在看同一个对象,而是一个当场重生的对象:VBA根据需要重新创建对象;这段对话已经结束。
If Target.Cells(1).Value = "Test" Then
    Cancel = True
    Load myForm
    myForm.Show
End If
Dim myForm As New UserForm1
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
    If Target.Cells(1).Value = "Test" Then
        Cancel = True
        With New UserForm1
            .Show
        End With
    End If
    Debug.Print "OK"
End Sub