如何检测事件是由最终用户触发的? (忽略代码触发的事件)
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"
- 在更改值之前记录要更改的范围的地址。
- 在onChanged 事件处理程序中,将事件参数与您之前记录的地址进行比较。如果匹配,则清除记录并退出事件处理程序。
这个问题来自我的一位正在开发 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"
- 在更改值之前记录要更改的范围的地址。
- 在onChanged 事件处理程序中,将事件参数与您之前记录的地址进行比较。如果匹配,则清除记录并退出事件处理程序。