Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 从按钮调用VBA表单会导致UserForm\u Initialize运行两次,从而破坏我的代码?_Excel_Vba - Fatal编程技术网

Excel 从按钮调用VBA表单会导致UserForm\u Initialize运行两次,从而破坏我的代码?

Excel 从按钮调用VBA表单会导致UserForm\u Initialize运行两次,从而破坏我的代码?,excel,vba,Excel,Vba,你好,精彩的VBA社区, 我对vba还是个新手,正在努力学习很多东西。提前感谢您查看我的代码以及我对所面临问题的描述 我在页面上有一个按钮,可以调用一个新的Userform 代码片段1: Sub btnShowDetails_Click() Call frmShowDeets.ShowDeets End Sub Public Sub ShowDeets() Dim frm As frmShowDeets Set frm = New frmShowDeets 'this line tr

你好,精彩的VBA社区, 我对vba还是个新手,正在努力学习很多东西。提前感谢您查看我的代码以及我对所面临问题的描述

我在页面上有一个按钮,可以调用一个新的Userform

代码片段1:

Sub btnShowDetails_Click()
    Call frmShowDeets.ShowDeets
End Sub
Public Sub ShowDeets()

Dim frm As frmShowDeets
Set frm = New frmShowDeets 'this line triggers the Userform_Initialize() event below
  frm.Show

End Sub
Private Sub UserForm_Initialize()

Dim comboBoxItem As Range

For Each comboBoxItem In ContactList.Range("tblContactList[CompanyName]")
                                            '^refers to unique values in a named range
  With Me.boxCompanySelection
    .AddItem comboBoxItem.Value
  End With
Next comboBoxItem

End Sub
Public Sub boxCompanySelection_Change()
  Call frmShowDeets.PullData
End Sub

Sub PullData()
Dim numCompanies As Long
  numCompanies = ContactList.Range("B6").Value 'this holds a count of the rows in the named range
Dim FoundCell As Range
  Set FoundCell = ContactList.Range("tblContactList[Company Name]").Find(What:=boxCompanySelection.Text, LookIn:=xlValues, LookAt:=xlWhole)

Dim CompanyRow As Long
  CompanyRow = FoundCell.Row

With ContactList
  'pull a bunch of the company's details
End With
End Sub
。。。调用“frmShowDeets”用户表单中的下一位代码:

代码片段2:

Sub btnShowDetails_Click()
    Call frmShowDeets.ShowDeets
End Sub
Public Sub ShowDeets()

Dim frm As frmShowDeets
Set frm = New frmShowDeets 'this line triggers the Userform_Initialize() event below
  frm.Show

End Sub
Private Sub UserForm_Initialize()

Dim comboBoxItem As Range

For Each comboBoxItem In ContactList.Range("tblContactList[CompanyName]")
                                            '^refers to unique values in a named range
  With Me.boxCompanySelection
    .AddItem comboBoxItem.Value
  End With
Next comboBoxItem

End Sub
Public Sub boxCompanySelection_Change()
  Call frmShowDeets.PullData
End Sub

Sub PullData()
Dim numCompanies As Long
  numCompanies = ContactList.Range("B6").Value 'this holds a count of the rows in the named range
Dim FoundCell As Range
  Set FoundCell = ContactList.Range("tblContactList[Company Name]").Find(What:=boxCompanySelection.Text, LookIn:=xlValues, LookAt:=xlWhole)

Dim CompanyRow As Long
  CompanyRow = FoundCell.Row

With ContactList
  'pull a bunch of the company's details
End With
End Sub
。。。触发:

代码片段3:

Sub btnShowDetails_Click()
    Call frmShowDeets.ShowDeets
End Sub
Public Sub ShowDeets()

Dim frm As frmShowDeets
Set frm = New frmShowDeets 'this line triggers the Userform_Initialize() event below
  frm.Show

End Sub
Private Sub UserForm_Initialize()

Dim comboBoxItem As Range

For Each comboBoxItem In ContactList.Range("tblContactList[CompanyName]")
                                            '^refers to unique values in a named range
  With Me.boxCompanySelection
    .AddItem comboBoxItem.Value
  End With
Next comboBoxItem

End Sub
Public Sub boxCompanySelection_Change()
  Call frmShowDeets.PullData
End Sub

Sub PullData()
Dim numCompanies As Long
  numCompanies = ContactList.Range("B6").Value 'this holds a count of the rows in the named range
Dim FoundCell As Range
  Set FoundCell = ContactList.Range("tblContactList[Company Name]").Find(What:=boxCompanySelection.Text, LookIn:=xlValues, LookAt:=xlWhole)

Dim CompanyRow As Long
  CompanyRow = FoundCell.Row

With ContactList
  'pull a bunch of the company's details
End With
End Sub
因此,此时,我要显示的表单在其一个组合框中加载了值,供用户选择。用户选择一家公司,Combobox_Change事件触发其他获取该公司信息的例程

代码片段4:

Sub btnShowDetails_Click()
    Call frmShowDeets.ShowDeets
End Sub
Public Sub ShowDeets()

Dim frm As frmShowDeets
Set frm = New frmShowDeets 'this line triggers the Userform_Initialize() event below
  frm.Show

End Sub
Private Sub UserForm_Initialize()

Dim comboBoxItem As Range

For Each comboBoxItem In ContactList.Range("tblContactList[CompanyName]")
                                            '^refers to unique values in a named range
  With Me.boxCompanySelection
    .AddItem comboBoxItem.Value
  End With
Next comboBoxItem

End Sub
Public Sub boxCompanySelection_Change()
  Call frmShowDeets.PullData
End Sub

Sub PullData()
Dim numCompanies As Long
  numCompanies = ContactList.Range("B6").Value 'this holds a count of the rows in the named range
Dim FoundCell As Range
  Set FoundCell = ContactList.Range("tblContactList[Company Name]").Find(What:=boxCompanySelection.Text, LookIn:=xlValues, LookAt:=xlWhole)

Dim CompanyRow As Long
  CompanyRow = FoundCell.Row

With ContactList
  'pull a bunch of the company's details
End With
End Sub
这就是它变得奇怪的地方。。。一旦显示表单并且用户选择组合框项目之一,触发组合框更改事件,代码就会中断,因为Range()的“What:=boxCompanySelection.Text”部分。Find方法读取为“empty”(即使代码段3要加载到公司名称中,而代码段4只有在用户从组合框中选择其中一个公司名称时才会触发),我也不需要构建一些东西来处理“未找到”异常,因为唯一可能的值应该是从我的命名范围中拉入的值

通过逐步浏览代码,我确定由于某种原因,代码段2和3在运行代码段4之前运行了两次。有人知道我的代码是什么导致了这种情况吗?我认为显示和加载组合框值的表单与代码段4读取的任何代码段之间存在断开连接ata来自

更奇怪的是,如果我从代码段2开始运行代码(忽略代码段1中的按钮调用),那么表单将按预期工作,并且从我所知道的情况来看,2和3只运行一次


这个问题可能很简单,我忽略了,但我就是不知道它是什么。再次感谢!

您必须理解表单是一个对象,与任何其他类模块完全相同,只是表单碰巧有一个设计器和一个基类,所以
UserForm1
继承
UserForm
类的成员

表单也有一个默认实例,许多教程只是愉快地跳过了这一非常重要但技术性的部分,这就把我们带到了堆栈溢出上,默认实例上意外存储了一个涉及全局状态的bug

Call frmShowDeets.ShowDeets
Call frmShowDeets.PullData
假设
frmShowDeets
是表单类的名称,并且假设这是对要运行的表单的第一个引用,那么当
点运算符执行并取消引用对象时,默认实例的
UserForm\u Initialize
处理程序将运行。然后
ShowDeets
方法将运行

Public Sub ShowDeets()

Dim frm As frmShowDeets
Set frm = New frmShowDeets 'this line triggers the Userform_Initialize() event below
  frm.Show

End Sub
该行在名为
frm
的本地实例上触发
UserForm\u Initialize
,该实例是同一类的一个完全独立的对象。
Initialize
处理程序在初始化(即创建)一个类的实例时运行。
Terminate
处理程序在该实例被销毁时运行

所以ShowDeets是一种“工厂方法”这将创建并显示
frmShowDeets
类/表单的新实例-换句话说,在默认实例上发生的任何事情都与该点无关:您正在处理的对象存在于
ShowDeets
范围内,命名为
frm
,一旦超出范围就会被销毁

完全删除
ShowDeets
方法。替换此方法:

Call frmShowDeets.ShowDeets
为此:

With New frmShowDeets
    .Show
End With
现在,
Initialize
处理程序不再在默认实例上运行

Call frmShowDeets.ShowDeets
Call frmShowDeets.PullData
您想要的是完全避免使用默认实例。将表单的代码隐藏中的所有
frmShowDeets
替换为
Me
(请参阅),这样就不会意外地将状态存储在默认实例中

Call frmShowDeets.ShowDeets
Call frmShowDeets.PullData
变得简单:

Call Me.PullData
甚至:

PullData

因为
Call
在任何地方都不需要,而且在类模块的代码中进行成员调用时,
Me
限定符总是隐式的。

阅读应该有助于理解这种奇怪之处。TL;DR:您的一些代码将状态存储在表单的默认实例中,而在其他地方,表单被视为它所访问的对象实际上是这样。因此,代码段1初始化默认实例;代码段2创建一个新实例,该实例也被反斜体化,然后代码段4调用代码段1正在使用但代码段2不知道的默认实例的
PullData
。尝试将调用
frmShowDeets.PullData替换为
Me.PullData
@MathieuGuindon感谢你链接那篇文章。这解释了很多我以前不知道的代码背后发生的事情。你的TLDR是非常棒的信息;非常感谢!:)@NelmanJayLouieVasquez为了让我的过程正常工作,修复程序做到了!非常感谢你!根据MathiewGuindon的回答,从“frmShowDeets”更改为“Me”似乎指示sub在第二个表单实例上调用PullData()?请注意,
ShowDeets
也是多余的。下面的答案解释了
Initialize
处理程序运行两次的原因。