Установка (Private WithEvents As Sheet1) sheetUI = Sheet1 вызывает ошибку 438: объект не поддерживает это свойство или метод - PullRequest
2 голосов
/ 10 апреля 2019

Я использую это превосходное учебное пособие в качестве основы для создания простого проекта Excel VBA "Hello World", использующего концепцию Матье Гиндона о написании кода VBA объектно-ориентированного программирования, обсуждаемого в серии статей оhttps://rubberduckvba.wordpress.com/ блог.

Я создал проект «без костей» без какой-либо модели, содержащей лист Excel (HelloSheet), View, ViewAdapter (включая интерфейсы ViewCommands и ViewEvents) и контроллер,Проект VBA компилируется без ошибок, но когда я пытаюсь запустить макрос «запись приложения», я получаю страшное «Ошибка времени выполнения 438: объект не поддерживает это свойство или метод».Это происходит внутри подпрограммы Class_Initialize () моего класса View, где я объявил «Private WithEvents sheetUI As HelloSheet» и пытаюсь установить «sheetUI = HelloSheet».

Здесь - это обзор дерева моего проекта, как видно из RubberDuck VBIDE.

Я попытался обновить ссылки на проект VBA, чтобы они точно соответствовали ссылкам на «Морской бой»образец проекта.Я также попробовал два разных подхода к реализации Ленивый объект / Слабая ссылка в классе View - тот, что в «Морском бою (WorksheetView) .xlsm», связанный в оригинальной статье vsподход, использованный в последней версии на 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).

Очевидно, что этот объем кода для таких простых задач является излишним - моя идея состоит в том, как только я получу эти основы, работающие над добавлением классов Model в проект и сопоставлением их с определенными областями (т.е.Tables / ListObjects) внутри рабочей книги.

Любая помощь будет принята с благодарностью!И слава всем, кто добрался до конца этого довольно длинного поста:)

1 Ответ

2 голосов
/ 10 апреля 2019
Private WithEvents sheetUI As HelloSheet

Private Sub Class_Initialize()
    sheetUI = HelloSheet
End Sub

sheetUI является ссылкой на объект, для присвоения которой требуется ключевое слово Set:

Private WithEvents sheetUI As HelloSheet

Private Sub Class_Initialize()
    Set sheetUI = HelloSheet
End Sub

Ошибка 438 генерируется при каждой попытке доступа к члену по умолчанию класса Worksheet, поскольку Worksheet не имеет члена по умолчанию - этот код воспроизводит ошибку из непосредственной панели :

?Sheet1

Или:

foo = Sheet1

Проверки Rubberduck должны предупредить об этом в разделе «Проблемы с качеством кода»:

Переменная объекта 'sheetUI' назначается без ключевого слова 'Set'.

...