【问题标题】:How to detect the event is trigger by end user? (ignore the event trigger by code)如何检测事件是由最终用户触发的? (通过代码忽略事件触发)
【发布时间】:2020-05-09 06:43:15
【问题描述】:

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

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

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

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

客户尝试过的解决方案:

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

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

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

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

【问题讨论】:

标签: excel office-js


【解决方案1】:

Office.js 尚未提供此类功能。

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

最可靠的方法是你的“当前尝试”

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

【讨论】:

  • 谢谢,我如何解决地址存储被再次删除后事件被触发的问题。因此处理程序无法比较地址并始终执行。
  • 为什么要在事件触发前删除地址存储?
  • 这正是问题所在,在事件被归档之前不应该删除地址存储。它应该像 1. 存储地址 2. 为单元格设置值 3. 进程表更改事件(如果来自存储地址忽略) 4. 删除地址存储 但它是这样的,因为事件是延迟触发的 1. 存储地址 2。将值设置为单元格 3. 删除地址存储 4. 处理工作表更改事件(无法进行存储地址比较)
  • 我认为问题在于“删除地址存储”的时机。请尝试在事件处理程序中删除地址存储,而不是在 await context.sync() 之后
【解决方案2】:

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

例如:


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

【讨论】:

  • 感谢您的回答,但是插件是网络插件,不是VBA,网络插件使用的是javascript API(这是异步模式),所以解决方案不起作用为我的客户。
  • 1.加载项的激活不是通过VBA吗? 2.您可以使用工作表中的一个单元格来检查 - 只需编辑答案。
  • 不,这不是VBA插件,这是JS web插件,使用office-js
  • 和js add-in一样,我们有一个context.sync(),所以API和Event的顺序是不按顺序的。您的答案类似于我验证过的全局变量解决方案(我也在我的原始帖子中分享了要点),它不起作用。
  • 你能帮我写office js 代码吗?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多