如何检测事件是由最终用户触发的? (忽略代码触发的事件)

How to detect the event is trigger by end user? (ignore the event trigger by code)

这个问题来自我的一位正在开发 excel 网络插件的客户,他们想检测事件是由最终用户触发还是由代码触发。

他们已经注册了一个 Worksheet.onChanged 事件处理程序。

他们想忽略由他们自己的代码触发的 onChanged 事件变化。并专注于处理事件处理程序应该只在用户更改值时完成。

场景: 加载项侦听 sheetChange 事件。加载项用户将值输入交叉表,加载项会将其推送到服务器。 但是插件API也可以对交叉表做一些修改,比如插件可以让用户单击并向下钻取更多的数据,他们的API逻辑将获取数据从服务中写入交叉表。但是,sheetChanged 事件也会被触发。

客户尝试过的解决方案:

第一次尝试: 我们试图在更改值之前注销事件处理程序。 然后我们在更改值后再次注册。 这没有用,因为注销是异步的,我们无法等待注销。

第二次尝试: context.runtime.enableEvents = 假 这是不可能的,因为我们仍然对其他事件感兴趣。

当前尝试: 我们在更改值之前存储更改范围的地址。 在 onChanged 处理程序中,我们比较地址。 如果相同我们不做逻辑。 之后,我们再次删除地址的存储。

我也尝试过使用全局标志并在事件处理程序中检查它,但它不起作用。这是我的要点:https://gist.github.com/lumine2008/2b51d94d20cdca9ac9a0e97029dfd95c

您可以创建一个变量来检查用户是否正在编辑。

例如:


Private Sub Worksheet_Activate()

    Static programChanging As Boolean

    programChanging = False

End Sub

Private Sub Worksheet_Change(ByVal Target As Range)

    If programChanging = False Then MsgBox("The User Is Changing")'*Do your code here*

End Sub

Private Sub Worksheet_SelectionChange(ByVal As Range)

    programChanging = True

    Range("A1").Value = "The Program Is Changing"

    programChanging = False

End Sub

您可以使用 programChanging 变量来检查用户是否正在更改,而不是程序是否正在更改,但原理保持不变。

~~编辑~~

您也可以使用其中一个单元格作为变量,例如:


Private Sub Worksheet_Change(ByVal Target As Range)

    If Range("A1").Value = "False" Then MsgBox("The User Is Changing")'*Do your code here*

End Sub

Private Sub Worksheet_SelectionChange(ByVal As Range)

    Range("A1").Value = "True"

    Range("B5").Value = "The Program Is Changing"

    Range("A1").Value = "False"

End Sub

Office.js还没有提供这样的功能。

一些解决方法,包括 a) context.runtime.enableEvents API、b) 全局标志,或 c) 在更改范围之前注销事件并稍后重新注册事件,不适用于跨平台. 它们在某些场景下会过度抑制事件,这意味着一些用户操作触发的事件也会被抑制。

最靠谱的方法就是你的"current try"

  1. 在更改值之前记录要更改的范围的地址。
  2. 在onChanged 事件处理程序中,将事件参数与您之前记录的地址进行比较。如果匹配,则清除记录并退出事件处理程序。