如果激活了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
答案 0 :(得分:5)
注意事件是SheetActivate
,而不是WorksheetActivate
- “工作表”的概念包含几种没有任何共同点的类型,除了“激活”的能力。 Excel对象模型中没有Sheet
类型 - Workbook.Sheets
集合包含各种类型的对象,包括 Chart
和Worksheet
对象。< / p>
Sh
事件中的SheetActivate
参数为Object
,因为Chart
和Worksheet
之间没有公共接口Chart
。
所以你需要做你做的事情:验证对象的类型,而不是假设你正在处理Worksheet
或TypeName
对象。
您应该使用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
)传递。假设处理程序将确定传递的对象类型,并根据发件人的类型采取适当的操作。