Reputation: 31
I'm facing a funny issue I don't understand.
In VBA, I want to load a Userform when the user double click on a cell, depending on the cell content. But depending on the condition I ask, Excel will crash once I exit the Sub (it keeps executing code even after the UserForm is closed).
This works:
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
And these three make Excel crash:
1.
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
2.
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
Dim myForm As New UserForm1
If Not Target.Cells(1).Value = "" Then
myForm.Show
End If
Debug.Print ("OK")
End Sub
3.
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 = "Test" Then
myForm.Show
End If
Debug.Print ("OK")
End Sub
I'm using an empty UserForm for testing
Upvotes: 3
Views: 137
Reputation: 71177
Cancelling the cell edit mode entry seems a pretty good way to limit the number of things that can go wrong.
There's more though.
Dim myForm As New UserForm1
That's creating an auto-instantiated UserForm1
object in local scope. Since Dim
statements aren't executable, that means regardless of whether you Show
the form or not, the object will be created as soon as the procedure scope is entered.
You can easily avoid creating that object unconditionally, and even avoid the need to declare a variable for it, using a With
block:
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
That way the form instance only ever gets created if it needs to. Big huge kudos for avoiding the default instance trap though - you can read more about that on my blog.
Notice I also removed the extraneous parentheses around the Debug.Print
argument list. Parentheses are actually actively harmful in procedure calls; you'll run into compile errors when you use them with multiple-parameter procedures, run-time errors when you need to pass an object reference, and logical bugs when you mean to pass a parameter ByRef
- the parentheses used like this, are forcing VBA to evaluate the expression as a value, and always pass the result ByVal
, regardless of whether the called procedure says it's taking a ByRef
parameter.
Use parentheses when you're calling a function and capturing its return value in a local variable.
Upvotes: 1
Reputation: 26640
Try changing the code within your If block so that it does a Cancel = True
to ignore the double-click action and also loads the form beforehand, like so:
If Target.Cells(1).Value = "Test" Then
Cancel = True
Load myForm
myForm.Show
End If
Upvotes: 3