不正确的async/await工作,Excel应用程序级插件中的Excel事件

本文关键字:Excel 应用程序 事件 插件 async await 工作 不正确 | 更新日期: 2023-09-27 18:15:11

我遇到了一个问题,在我的外接程序中使用async/await,我有自定义任务窗格,用户可以用它下载一些数据,所以有问题:

  1. 等待操作完成后,控件未返回到先前的执行上下文。我用windows窗体创建了一个例子,并粘贴了相同的方法等待,它工作得很好-我可以在等待操作后使用表单控件,但不是在加载项中,我必须调用自定义任务窗格Invoke方法。简单的例子:

    private void SearchPaneButton_Click(object sender, EventArgs e)
    {
        Search();
    }
    private async void Search()
    {
        var searchText = SearchTextBox.Text;
        SearchPaneButton.Text = "Loading…";
        var data = await new DataServiceClient().GetDataAsync(searchText);
        this.Invoke((MethodInvoker)(() =>
        {
            SearchPaneButton.Text = "Search";
            ToggleWorkbookEvents();
        }));
    }
    
  2. 在我的加载项中,我需要处理一些事件-工作表更改,工作表激活/停用,但这些事件消失并且在等待操作后不被触发,我必须在每次等待使用后使用"切换"(删除+添加)事件。简单的例子:

    private void ToggleWorkbookEvents()
    {
        var excel = Globals.MyAddIn.Application;
        //need to ensure event will not be set twice
        excel.SheetActivate -= CheckSheetForData;
        excel.SheetActivate += CheckSheetForData;
        if (excel.ActiveWorkbook != null)
        {
            var activeSheet = Globals.MyAddIn.GetActiveWorksheet();
            //need to ensure event will not be set twice
            activeSheet.Change -= Worksheet_Changed;
            activeSheet.Change += Worksheet_Changed;
        }
    }
    

所以也许vsto框架不能支持新功能(如async await)的最后一个版本。net框架?

不正确的async/await工作,Excel应用程序级插件中的Excel事件

这是Office插件长期存在的问题:它们不提供SynchronizationContext

正如我在我的博客上提到的,你可以通过确保你有一个合适的SynchronizationContext来解决这个问题。这是一个有点粗糙,但它工作:

private async void SearchPaneButton_Click(object sender, EventArgs e)
{
  if (SynchronizationContext.Current == null)
    SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
  await SearchAsync();
}
private async Task SearchAsync()
{
  var searchText = SearchTextBox.Text;
  SearchPaneButton.Text = "Loading…";
  var data = await new DataServiceClient().GetDataAsync(searchText);
  SearchPaneButton.Text = "Search";
  ToggleWorkbookEvents();
}

至于"切换事件"的问题,我不知道。

当涉及到您的第二个问题-从工作表,工作簿等中解除绑定的事件时,您必须将对目标对象的引用存储为绑定这些事件的类的属性或字段。例如,在ToggleWorkbookEvents方法中,您引用Application作为局部变量,您可以尝试这样存储它:

private Microsoft.Office.Interop.Excel.Application _application = Globals.MyAddIn.Application;

我认为这是由于目标事件处理程序在垃圾收集期间被删除所致。

我基于Peter的回答:https://stackoverflow.com/a/58524311/6757641