在VB.net中执行Excel中的事件,主程序被初始化

zfybs 2014-10-17 12:34:44
问题描述:具体的需求比较复杂,我就不说了,在出现问题后,我将问题进行了排查,最后发现问题所在,并简化程序如下:

1、新建一个Visual Basic.NET的窗口项目,然后在项目中引用了Excel。

2、然后在主程序启动时创建了一个新的Excel程序,为了执行Excel关闭的事件,添加了一个新的Workbook以用来引发Excel的Application.WorkbookBeforeClose事件

3、测试时一共执行三步操作: 先点击主程序窗口,此时立即窗口中显示:
在主程序中:123
在testclass类中:123


4、然后点击关闭Excel程序,此时立即窗口中显示:
在testclass类的WorkbookBeforeClose事件中:0
说明:在调试时,发现在提取Form1.WillReNew属性值时,会再次进入类Form1,对其中的每一个属性值进行初始化!!!
我猜测问题的关键词可能与“线程”有关。


5、最后再点击主程序窗口,此时立即窗口中显示:
在主程序中:123
在testclass类中:123



问题就是:
为什么在第4步时要对Form1进行初始化(类似于重新声明了一个Form1的对象),这样我就没法在这个事件中对原来的主程序Form1进行相关操作了。
而第5步又说明原来的Form1的对象还是存在的。


代码如下:
1.在窗口类Form1:
******************************************************
Imports Microsoft.Office.Interop.Excel
Public Class Form1

Private ReNew As Integer
Public Property WillReNew As Integer
Get
Return ReNew
End Get
Set(value As Integer)
ReNew = value
End Set
End Property

Dim b As testclass
Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click
Debug.Print("在主程序中:" & Me.WillReNew)
'第一次点击时返回123,第二次点击时还是返回123
Call b.test()
End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
ReNew = 123 '对Form1的WillReNew属性进行初始化,为123。
b = New testclass
b.application = New Application
b.application.Visible = True
b.application.Workbooks.Add()
End Sub

End Class


2、在类testclass中:
****************************************
Imports Microsoft.Office.Interop.Excel
Public Class testclass

Private WithEvents app As Application
Public Property application As Application
Get
Return app
End Get
Set(value As Application)
app = value
End Set
End Property

Public Sub test()
Debug.Print("在testclass类中:" & Form1.WillReNew)
' '第一次点击时返回123,第二次点击时还是返回123
End Sub

' 出现问题的事件
Private Sub refresh(wkbk As Workbook, ByRef cancel As Boolean) _
Handles app.WorkbookBeforeClose

Debug.Print("在testclass类的WorkbookBeforeClose事件中:" & Form1.WillReNew)

'这里Form1.WillReNew返回integer的初始值0,
'在调试中发现它进入Form1中对其每一个属性或域值进行了初始化
'(类似于重新声明了一个Form1的对象)
'猜测可能是线程的问题,因为下一次点击窗口时还是能返回123

End Sub

End Class
...全文
1004 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
zfybs 2014-10-18
  • 打赏
  • 举报
回复
引用 15 楼 Tiger_Zhao 的回复:
自己的设计框架自己分析,为什么会是两个实例?
我觉得可能是线程的问题,因为执行上面的test方法与下面的excel事件方法的是两个不同的线程。 但是在这方面我的知识还不够,我想是不是原主程序依附于主线程存在,但好像没听说过有这样的说法。如果form1就是表示原主程序的对象的话,那多个线程中应该调用的还是同一个对象的数据。 至于您说的两个实例的问题,我觉得我没在任何地方创建出两个主程序的实例啊,一共就两个类,代码就那么几行,都列出来了啊。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
引用 5 楼 Tiger_Zhao 的回复:
你确定是一个实例? Debug.Print 中带上 Form1.Handle
我刚才找到了其Handle属性,那我拿到这个属性值后该怎么办呢? 能给出具体的代码吗,我就是要获取原来的那个Form1的ReNew 属性值,而不是要它重新初始化一个Form1,再返回给我ReNew 的初始值。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
有没有可能是线程的问题,因为第4步与第5步在调试时返回的结果不一样,而它们的线程是不一样的。

第4步在Excel的事件中:Form1被重新初始化并返回值0


第5步在Form1窗体的事件中:调用的还是主程序的那个窗体,返回值123.

zfybs 2014-10-17
  • 打赏
  • 举报
回复
引用 7 楼 Tiger_Zhao 的回复:
我 VS2008,有 Handle 属性。
那关于上面那是Form1是否是否能表示主程序的实例的问题,您怎么看呢?
Tiger_Zhao 2014-10-17
  • 打赏
  • 举报
回复
我 VS2008,有 Handle 属性。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
引用 5 楼 Tiger_Zhao 的回复:
你确定是一个实例?
Debug.Print 中带上 Form1.Handle


1、 你确定是一个实例?——我觉得是吧,在上面的步骤3和步骤5里都可以直接用的,而且我在其他的程序中这么用好像也没有出现问题;

2、 Debug.Print 中带上 Form1.Handle——这个能说得具体些吗,我好像没有找到Form1的handle属性或者方法。
Tiger_Zhao 2014-10-17
  • 打赏
  • 举报
回复
你确定是一个实例?
Debug.Print 中带上 Form1.Handle
zfybs 2014-10-17
  • 打赏
  • 举报
回复
引用 3 楼 Tiger_Zhao 的回复:
Debug.Print("在testclass类中:" & Form1.WillReNew) 
你没有使用自己的实例变量,直接使用Form1,这等于是一个隐式定义的全局变量
Public Form1 As New Form1
这样窗体关闭(释放)后,再访问 Form1.WillReNew 等于是新建了一个实例,但有没有加载窗体所以没有 Load 事件,ReNew 变量当然只有默认的 0 值了。
第一个问题:Form1不是作为整个项目的启动窗口,可以直接以“Form1”作为其实例的吗? 第二个问题:你上面讲的“窗体关闭(释放)”,我这里并没有这一操作啊。我只在对打开的Excel程序执行了关闭事件,而实际证明,这里对Excel执行任何事件(将上面的WorkbookBeforeClose事件换成Excel的Application的其他事件),只要是按上面的这种方式,都会出现重新初始化一个Form1,并返回其初始值的问题。
Tiger_Zhao 2014-10-17
  • 打赏
  • 举报
回复
Debug.Print("在testclass类中:" & Form1.WillReNew) 

你没有使用自己的实例变量,直接使用Form1,这等于是一个隐式定义的全局变量
Public Form1 As New Form1

这样窗体关闭(释放)后,再访问 Form1.WillReNew 等于是新建了一个实例,但有没有加载窗体所以没有 Load 事件,ReNew 变量当然只有默认的 0 值了。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
我觉得可能是线程的问题,因为执行上面的test方法与下面的excel事件方法的是两个不同的线程。
但是在这方面我的知识还不够,我想是不是原主程序依附于主线程存在,但好像没听说过有这样的说法。如果form1就是表示原主程序的对象的话,那多个线程中应该调用的还是同一个对象的数据。
至于您说的两个实例的问题,我觉得我没在任何地方创建出两个主程序的实例啊,一共就两个类,代码就那么几行,都列出来了啊。
Tiger_Zhao 2014-10-17
  • 打赏
  • 举报
回复
自己的设计框架自己分析,为什么会是两个实例?
zfybs 2014-10-17
  • 打赏
  • 举报
回复
引用 13 楼 Tiger_Zhao 的回复:
这个对象之间的关系只有你自己清楚了。 简单地说就是要把显示窗体的实例传给 testclass,通过传入实例而不是全局的 Form1 去取 WillReNew 。
首先非常感谢您的点拨。按您的思路来,确实是做到了,解决了第二个“怎么办”的问题: 在testClass中添加一个mainForm的字段以获取主程序的对象。但是注意到,我这里故意是从testClass的Test方法中用Form1为其赋值的,而不是在Form1类中用b.main = Me来赋值的。然后在事件代码中将Form1改成mainForm。 修改了testClass类的代码如下:
Imports Microsoft.Office.Interop.Excel
Public Class testclass

    Public ev_event()

    Public mainForm As Form1        '在这里索引主程序

    Private WithEvents app As Application
    Public Property application As Application
        Get
            Return app
        End Get
        Set(value As Application)
            app = value
        End Set
    End Property

    Public Sub test()
        Me.mainForm = Form1
        '在第3步时,将Form1的实例传给testclass的mainform字段,
        '但是问题是,这里还是能将form1作为主程序的实例的
        Debug.Print("在testclass类中:" & Form1.WillReNew)
    End Sub

    Private Sub refresh() Handles app.WindowResize
        Debug.Print("在testclass类的WorkbookBeforeClose事件中:" & mainForm.WillReNew)        '返回integer的初始值0
    End Sub
End Class
所以第一个问题还是没有解决:为什么第4步与第5步中会出现这种不同。 都是调用 Form1.WillReNew,为什么会一个要能索引到主程序对象,而一个却要重新初始化一个对象???
Tiger_Zhao 2014-10-17
  • 打赏
  • 举报
回复
这个对象之间的关系只有你自己清楚了。
简单地说就是要把显示窗体的实例传给 testclass,通过传入实例而不是全局的 Form1 去取 WillReNew 。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
在测试中发现,不仅是WorkbookBeforeClose事件,而是application的所有事件都会有这个问题。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
引用 11 楼 Tiger_Zhao 的回复:
WillReNew 不同的地方 Handle 值是否一致。 不一致就是多个实例,你的设计就有问题了。
刚测试了一下,发现不一致。 那我该怎么来解决这个问题呢? 一直到现在,“这个问题出现的原因” 和 “如何来正确地获取原来的主程序对象”,这两个问题还是没有解决。
zfybs 2014-10-17
  • 打赏
  • 举报
回复
自己先顶。 看在我描述得如此清楚全面的份上,请各位大神不吝赐教。
Tiger_Zhao 2014-10-17
  • 打赏
  • 举报
回复
WillReNew 不同的地方 Handle 值是否一致。
不一致就是多个实例,你的设计就有问题了。

863

社区成员

发帖
与我相关
我的任务
社区描述
VB COM/DCOM/COM+
c++ 技术论坛(原bbs)
社区管理员
  • COM/DCOM/COM+社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧