【问题标题】:How to avoid cell selection in Excel while processing in a VSTO add-in如何在 VSTO 加载项中处理时避免在 Excel 中选择单元格
【发布时间】:2018-01-16 11:30:43
【问题描述】:

我开发了一个 Excel 加载项,可以用数据填充工作表。

填充数据的主循环是:

Excel.Worksheet sheet = workbook.Sheets.Add(After: workbook.Sheets[workbook.Sheets.Count]);
int newRow = 2;
// Llena la hoja con el maestro
foreach (var producto in maestro)
{
    sheet.Cells[newRow, 1].Formula = producto.SKU.ToFormula();
    sheet.Cells[newRow, 2].Value = producto.Descripcion;
    sheet.Cells[newRow, 3].Value = producto.Linea;
    sheet.Cells[newRow, 4].Value = producto.Familia;
    sheet.Cells[newRow, 5].Value = producto.UltimoCorrelativo;
    sheet.Cells[newRow, 6].Value = producto.FechaCreacion;
    sheet.Cells[newRow, 7].Value = producto.FechaModificacion;

    newRow++;
}

然而,一切都完美无缺,因为这个过程是在 STA 线程中运行的,为了不冻结 UI,用户可以在处理时执行其他操作。其中一项操作是单击单元格。在任何指令中,该操作都会导致应用程序在 for 循环内崩溃。

异常是 HRESULT: 0x800AC472

怎样才能避免呢?

【问题讨论】:

  • 也许你可以尝试在处理期间设置一个等待光标,见stackoverflow.com/a/39544078/3205529
  • 这不是一个选项,因为这并不能避免用户点击任何地方。另一个选项是使用 VSTO 指令避免用户输入,但不允许单击取消按钮。最后,我使用 try catch 块,如果用户单击单元格并引发异常,则会出现一个消息框,允许用户重试处理。
  • 好吧,另一个想法:也许 application.screenupdating 设置为 False,然后设置为 True。但我不确定它是否会阻止选择。

标签: c# excel vsto


【解决方案1】:

Excel 并不真正支持多线程。 如果您收到错误0x800AC472,这意味着 Excel 正忙于执行一项操作,同时请求了第二项操作,例如当您填充单元格时,用户点击了一个单元格 - 反之亦然。

避免此错误的推荐解决方案是在短时间内重试。 因此,如果System.Runtime.InteropServices.COMException 被抛出and (uint) e.HResult == 0x800AC472,那么执行System.Threading.Thread.Sleep( someMilleseconds ) 并重试。在循环中执行此操作,并在最多 n 次重试后重新引发异常。

【讨论】:

    【解决方案2】:

    如果 UI 未冻结,并且 Excel 上没有模式窗口,用户始终可以选择单元格。你无法阻止它。所以,如果你在 Excel 工作表上做长操作,你绝对需要设置Application.ScreenUpdating = false。实际上,您可以在另一个 STA 线程中创建一个窗口并将取消按钮放在那里。当你得到异常时,你可以设置 screenupdating = true。 但在你的情况下,我建议另一种方式。从您的示例来看,您似乎只想为单元格设置值,而这些单元格在一个范围内:

    sheet.Cells[newRow, 1].Formula = producto.SKU.ToFormula();
    sheet.Cells[newRow, 2].Value = producto.Descripcion;
    sheet.Cells[newRow, 3].Value = producto.Linea;
    sheet.Cells[newRow, 4].Value = producto.Familia;
    sheet.Cells[newRow, 5].Value = producto.UltimoCorrelativo;
    sheet.Cells[newRow, 6].Value = producto.FechaCreacion;
    sheet.Cells[newRow, 7].Value = producto.FechaModificacion;
    

    有更好更快的方法来做到这一点。您可以从数组中设置整个范围的值。这是good example。这同样适用于公式。因此,每个产品都只有 2 个操作,而不是每个产品的 7 个操作。经过这样的优化,也许你甚至不需要 Cansel 按钮了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-08
      • 2019-12-15
      • 1970-01-01
      • 2018-07-06
      • 2016-12-14
      相关资源
      最近更新 更多