我正在使用这个优秀的教程作为基础,利用 Mathieu Guindon 编写面向对象编程 VBA 代码的概念创建一个简单的“Hello World”Excel VBA 项目,该概念在https://rubberduckvba.wordpress上的一系列文章中进行了讨论。 com/博客。
我创建了一个“基本”项目,没有包含 Excel 工作表 (HelloSheet)、视图、ViewAdapter(包括 ViewCommands 和 ViewEvents 接口)和控制器的任何模型。VBA 项目编译时没有错误,但是当我尝试运行“应用程序条目”宏时,我得到了可怕的“运行时错误 438:对象不支持此属性或方法”。这发生在我的 View 类的 Class_Initialize() 子类中,我在其中声明了“Private WithEvents sheetUI As HelloSheet”并尝试设置“sheetUI = HelloSheet”。
这是我的项目树的概述,如 RubberDuck VBIDE 中所示。
我尝试更新 VBA 项目引用以完全匹配“战舰”示例项目的引用。我还尝试了两种不同的方法来实现 View 类中的惰性对象/弱引用-原始文章中链接的“Battleship (WorksheetView).xlsm”中的一种与GitHub 上最新版本中使用的方法,更具体地说:
Private adapter As ***IWeakReference***
Private WithEvents sheetUI As HelloSheet
Private Sub Class_Initialize()
sheetUI = HelloSheet
End Sub
Private Property Get ViewEvents() As ISheetViewEvents
Set ViewEvents = adapter ***.Object***
End Property
VS
Private adapter As ***SheetViewAdapter***
Private WithEvents sheetUI As HelloSheet
Private Sub Class_Initialize()
sheetUI = HelloSheet
End Sub
Private Property Get ViewEvents() As ISheetViewEvents
Set ViewEvents = ***adapter***
End Property
..但“运行时错误 438:对象不支持此属性或方法”仍然存在。
以下是工作表、类、接口等中所有相关的代码拆分:
1)HelloSheet(常规Excel工作表代码隐藏):
'@Folder("HelloWorld.View.Worksheet")
Option Explicit
Public Event DoubleClick(ByVal clickedRow As Integer)
Public Sub HideShape(shapeName As String)
Dim currentShape As Shape
Set currentShape = Me.Shapes(shapeName)
currentShape.Visible = msoFalse
End Sub
Public Sub ShowShape(shapeName As String)
Dim currentShape As Shape
Set currentShape = Me.Shapes(shapeName)
currentShape.Visible = msoTrue
End Sub
Public Sub OnLaunchCommand()
ShowShape ("WarningTriangle")
End Sub
Public Sub TempManualHide()
HideShape ("WarningTriangle")
End Sub
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
RaiseEvent DoubleClick(Target.Row)
End Sub
Public Sub PreviewSelectedRecord(ByVal selectedRow As Integer)
Me.Cells(1, 1).Value2 = "Row is " & CStr(selectedRow)
End Sub
2)SheetView类:
'@Folder("HelloWorld.View.Worksheet")
Option Explicit
Implements ISheetViewCommands
Private adapter As SheetViewAdapter ' IWeakReference
Private WithEvents sheetUI As HelloSheet
Private Sub Class_Initialize()
sheetUI = HelloSheet
End Sub
Private Property Get ViewEvents() As ISheetViewEvents
Set ViewEvents = adapter '.Object
End Property
':GameSheet event handlers
':Messages sent from the view
':***************************
Private Sub sheetUI_DoubleClick(ByVal clickedRow As Integer)
ViewEvents.PreviewSelectedRecord clickedRow
End Sub
':IGridViewCommands
':Messages sent from the controller
':*********************************
Private Property Set ISheetViewCommands_Events(ByVal value As ISheetViewEvents)
Set adapter = value ' WeakReference.Create(Value)
End Property
Private Property Get ISheetViewCommands_Events() As ISheetViewEvents
Set ISheetViewCommands_Events = adapter '.Object
End Property
Private Sub ISheetViewCommands_OnLaunchCommand()
sheetUI.OnLaunchCommand
End Sub
Private Sub ISheetViewCommands_OnPreviewSelectedRecord(ByVal selectedRow As Integer)
sheetUI.PreviewSelectedRecord selectedRow
End Sub
3) ISheetViewEvents 接口:
'@Folder("HelloWorld.View")
'@Interface
Option Explicit
Public Sub PreviewSelectedRecord(ByVal selectedRow As Integer)
End Sub
4) ISheetViewCommands 接口:
'@Folder("HelloWorld.View")
'@Interface
Option Explicit
'@Description("Gets/sets a weak refererence to the view events.")
Public Property Get Events() As ISheetViewEvents
End Property
Public Property Set Events(ByVal value As ISheetViewEvents)
End Property
Public Sub OnLaunchCommand()
End Sub
Public Sub OnPreviewSelectedRecord(ByVal selectedRow As Integer)
End Sub
5)SheetViewAdapter 类(PredeclaredId / 有默认实例):
'@Folder("HelloWorld.View")
Option Explicit
'@PredeclaredId
Implements ISheetViewCommands
Implements ISheetViewEvents
Public Event OnPreviewCurrentSelectedRecord(ByVal selectedRow As Integer)
Private Type TAdapter
SheetViewCommands As ISheetViewCommands
End Type
Private this As TAdapter
Public Function Create(ByVal view As ISheetViewCommands) As SheetViewAdapter
With New SheetViewAdapter
Set .SheetViewCommands = view
Set view.Events = .Self
Set Create = .Self
End With
End Function
Public Property Get Self() As SheetViewAdapter
Set Self = Me
End Property
'@Description("Gets/sets a reference that exposes commands to send to the view.")
Public Property Get SheetViewCommands() As ISheetViewCommands
Set SheetViewCommands = this.SheetViewCommands
End Property
Public Property Set SheetViewCommands(ByVal value As ISheetViewCommands)
Set this.SheetViewCommands = value
End Property
':IGridViewEvents
':Messages sent from the view
':***************************
Private Sub ISheetViewEvents_PreviewSelectedRecord(ByVal selectedRow As Integer)
RaiseEvent OnPreviewCurrentSelectedRecord(selectedRow)
End Sub
':IGridViewCommands
':Messages sent from the controller
':*********************************
Private Property Set ISheetViewCommands_Events(ByVal value As ISheetViewEvents)
Err.Raise 5, TypeName(Me), "Invalid use of property"
End Property
Private Property Get ISheetViewCommands_Events() As ISheetViewEvents
Set ISheetViewCommands_Events = Me
End Property
Private Sub ISheetViewCommands_OnLaunchCommand()
this.SheetViewCommands.OnLaunchCommand
End Sub
Private Sub ISheetViewCommands_OnPreviewSelectedRecord(ByVal selectedRow As Integer)
this.SheetViewCommands.OnPreviewSelectedRecord selectedRow
End Sub
6)HelloController类:
'@Folder("HelloWorld")
Option Explicit
Private viewCommands As ISheetViewCommands
Private WithEvents viewAdapter As SheetViewAdapter
Public Sub Launch(ByVal adapter As SheetViewAdapter)
Set viewAdapter = adapter
Set viewCommands = adapter
viewCommands.OnLaunchCommand
End Sub
Private Sub viewAdapter_OnPreviewCurrentSelectedRecord(ByVal selectedRow As Integer)
viewCommands.OnPreviewSelectedRecord selectedRow
End Sub
7) 最后是作为入口点的“宏”标准模块。这是我遇到错误的地方(“Set view = New SheetView”行):
'@Folder("HelloWorld")
'@Description("Application entry points.")
Option Explicit
'@Ignore MoveFieldCloserToUsage
Private controller As HelloController
Public Sub LaunchWorksheetInterface()
Dim view As SheetView
Set view = New SheetView
Set controller = New HelloController
controller.Launch SheetViewAdapter.Create(view)
End Sub
假设我可以绕过入门级错误,我会期待一个非常简单的功能:
1) 隐藏的 Excel 形状在 HelloSheet(OnLaunchCommand)上可见;
2)当双击一个单元格时,它所在的行将在同一个工作表的单元格A1中报告(Worksheet_BeforeDoubleClick事件)。
显然,这种简单任务的代码量是多余的——我的想法是,一旦我掌握了这些基础知识,就可以将模型类添加到项目中并将它们映射到工作簿中的某些区域(即表/列表对象)。
任何帮助将不胜感激!对任何完成这篇相当长的帖子的人表示敬意:)