Class 如何将WithEvents关键字与全局变量一起使用?
我试图在VB6模块中声明一个变量,如下所示:Class 如何将WithEvents关键字与全局变量一起使用?,class,events,vb6,module,Class,Events,Vb6,Module,我试图在VB6模块中声明一个变量,如下所示: Public WithEvents MyObject As MyClass 帮助文件指出,WithEvents只能在类模块中使用。为什么不能在.bas模块中使用 我正在处理的遗留代码在模块中全局声明了一个对象。我想将with events添加到此声明中,但我需要保持对象的全局性,因为许多其他表单等都引用该对象。如何在对代码中断最小的情况下实现这一点?VB中的事件是一个相当复杂的COM机制的包装器。本质上,在这种机制中,涉及的所有内容都必须是实现接口
Public WithEvents MyObject As MyClass
帮助文件指出,WithEvents
只能在类模块中使用。为什么不能在.bas
模块中使用
我正在处理的遗留代码在模块中全局声明了一个对象。我想将
with events
添加到此声明中,但我需要保持对象的全局性,因为许多其他表单等都引用该对象。如何在对代码中断最小的情况下实现这一点?VB中的事件是一个相当复杂的COM机制的包装器。本质上,在这种机制中,涉及的所有内容都必须是实现接口IConnectionPoint或IConnectionPointContainer的COM类。BAS模块是遗留BASIC的一部分,与VB类不同,它不是作为COM类实现的。我想他们本可以在COM中将BAS文件重新实现为单例类型的对象(就像他们对全局多用途类所做的那样),但他们没有。因此,不幸的是BAS文件不能与事件一起使用
至于问题的最简单解决方案,您需要利用对象变量只是对对象的引用,而不是对象本身的引用这一事实。我想您希望事件消息到达所需的最高级别对象,以便您能够控制您感兴趣的应用程序的位。确认这个地方。例如,您可能有一个主窗体,您确信它将是第一个加载的对象,最后一个卸载的对象。作为此对象初始化的一部分,传入对全局对象的引用,并将其设置为WithEvents模块级别变量。你现在控制了局面
但是!!这是非常重要的!!您必须确保在应用程序关闭之前及时清除此引用,以防您的表单(或其他任何形式)有任何循环引用。在这种情况下,Form_Unload事件非常理想。我不确定您的应用程序有多大,但有几种方法可以做到这一点。下面是我要做的,尽管这可能需要你15分钟左右的时间来重构你的应用程序来使用它 首先将模块中的所有公共和全局方法及成员复制到一个名为(例如)clsApplication的类中 其次,在现在为空的模块(我们称之为modGlobal)中,将
公共属性Get Application()声明为clsApplication
。继续添加一个二传手
第三,在启动程序的Sub Main()
中,将其添加为第一行Set modGlobal.Application=New clsApplication
现在,您已经将模块替换为一个全局类,该类可以侦听在应用程序范围内发生的事件。在应用程序的其余部分中,您可以访问全局状态,如Application.Config
或Application.GetUser()
或您在全局级别保留的任何其他内容
当然,您可以将其应用于希望与事件一起使用的变量,但无论如何,您都应该真正考虑从模块中获取代码
刚刚看到@Mark的评论。微小的方法是我一直坚持的。如果事件类是MyEventSource,则创建一个名为MyEventSourceListener的类,该类具有一个名为
Target
的属性,您将对象传递到该属性中,并使用Events私下声明该属性。然后MyEventSourceListener可以接收事件并将它们转发回您的模块
我不喜欢它,因为它是一种黑客行为,将代码放回模块中,但这可能是最方便的方法。编写一个类,接受全局对象作为参数并接收其事件
' Class MySink
Private WithEvents m_oSink As MyClass
Friend Sub frInit(oSink As MyClass)
Set m_oSink = oSink
End Sub
Private Sub m_oSink_MyEvent()
'--- implement event
End Sub
在.bas
模块中创建此类的实例
Public g_oMyObject AS MyClass
Private m_oMySink As MySink
Sub Main()
Set g_oMyObject = New MyClass
Set m_oMySink = New MySink
m_oMySink.frInit g_oMyObject
End Sub
一种简单方法的案例 对于一个类,甚至是一个用户控件(实际上只是一种特殊的类),在整个程序中具有广泛使用的属性和方法,有时是非常有用的 如果主要关注的是广泛使用无状态的“实用工具”方法(例如,一些与Web相关的方法具有URL编码、实体编码等方法),那么只需声明一个附加的全局实例“没有”事件,就可以相当便宜,而不必导致加载大量内部状态(数组、集合等)。由于您的程序无论如何都需要所有的代码,并且内存中只有一个副本,所以第二个实例可能相当便宜 另一种选择是将这些“公共”操作甚至属性值分解成单独的类或静态(BAS)模块 但有时,您有一个相当复杂的用户控件或类,您不想通过重构为单独的模块或以其他方式修改来自定义它。也许您可以维护一个通用的标准版本,以便在不同的项目中使用。也许这是一个第三方图书馆,你甚至没有它的来源。不管怎样 需要考虑的事情 这给我们带来了另一种可能对你有用的技术,即使用欧文·梅恩韦不朽的话来说,这是“不适合盲童的”。如果你有足够的经验来使用它,那么你应该已经想到了——但我们中没有人有完美的记忆力(如果我们确实花时间阅读过那本精美的手册) 因此,也许出于某种原因,这对你不起作用,你已经考虑并放弃了这个想法 您的容器对象(表单、UserControl、父类等)可以在初始化时小心地设置对相关对象实例的全局引用,并在终止时删除引用。这样做时应注意避免循环引用或孤立引用,因为循环引用或孤立引用会阻止其他对象甚至整个程序卸载 约翰尼后藤不应该轻易地接受或使用这一点。但是如果你知道你在VB中做什么,并且已经阅读并理解了t