为什么在以下VBA代码中使用Object类型而不是Sheet类型用于变量声明?

时间:2017-02-24 15:25:06

标签: excel vba excel-vba

如果激活了Chart,则以下代码会将用户返回到旧工作表,并在返回之前显示Chart中包含的数据点数。我想知道为什么变量Sh在两个事件处理程序过程中被定义为Object而不是Sheet。变量OldSheet也是如此。

Dim OldSheet As Object

Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
    Set OldSheet = Sh
End Sub

Private Sub Workbook_SheetActivate(ByVal Sh As Object)
    Dim Msg As String
    If TypeName(Sh) = "Chart" Then
        Msg = "This chart contains "
        Msg = Msg & ActiveChart.SeriesCollection(1).Points.Count
        Msg = Msg & " data points." & vbNewLine
        Msg = Msg & "Click OK to return to " & OldSheet.Name
        MsgBox Msg
        OldSheet.Activate
    End If
End Sub

2 个答案:

答案 0 :(得分:5)

因为在Excel中没有“工作表”这样的东西。

注意事件是SheetActivate,而不是WorksheetActivate - “工作表”的概念包含几种没有任何共同点的类型,除了“激活”的能力。 Excel对象模型中没有Sheet类型 - Workbook.Sheets集合包含各种类型的对象,包括 ChartWorksheet对象。< / p>

Sh事件中的SheetActivate参数Object,因为ChartWorksheet之间没有公共接口Chart

所以你需要做你做的事情:验证对象的类型,而不是假设你正在处理WorksheetTypeName对象。

您应该使用TypeOf运算符代替使用Private Sub Workbook_SheetActivate(ByVal Sh As Object) If TypeOf Sh Is Excel.Worksheet Then Debug.Print "Worksheet!" ElseIf TypeOf Sh Is Excel.Chart Then Debug.Print "Chart!" Else Debug.Print "Something else!" End If End Sub 函数并因此使用字符串类型检查:

Object

参数为IWorkbookEvents允许将来的版本激活一种类型,这种类型在{{1}中写入事件声明时无法实现每个Workbook对象实现的隐藏接口。

答案 1 :(得分:3)

答案的简短版本是必须声明为Object。这些事件通过COM源接收器“触发”,并将IDispatch指针(在VBA中称为Object)返回给具有订阅回调函数的任何事件。 ByVal Sh As Object参数传递给回调函数,以便事件处理程序可以确定哪个对象负责引发事件。它在dispinterface WorkbookEvents上的Excel类型库中声明如下:

[id(0x00000619), helpcontext(0x0007ad30)]
void SheetActivate([in] IDispatch* Sh);

即使不考虑其实现的COM管道,也必须声明为Object,因为Sheets集合同时包含Worksheet和{{1对象,如果激活了 类型的选项卡,则会触发该事件。这两种类型不共享一个公共接口,但它们都会同时发起相同的事件。这意味着为了将源对象传递给事件处理程序, 必须 作为后期绑定(Chart)传递。假设处理程序将确定传递的对象类型,并根据发件人的类型采取适当的操作。