我开发了一个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
如何避免这种情况?
答案 0 :(得分:0)
Excel并不真正支持多线程。
如果您收到错误0x800AC472
,则表示Excel正忙于处理某项操作,同时请求执行第二次操作,例如当您填充单元格时,用户单击一个单元格 - 反之亦然。
避免此错误的建议解决方案是在短时间后重试。
因此,如果System.Runtime.InteropServices.COMException
被抛出and (uint) e.HResult == 0x800AC472
,请执行System.Threading.Thread.Sleep(
someMilleseconds )
,然后重试。在循环中执行此操作,并在最多 n 重试后重新抛出异常。
答案 1 :(得分:0)
如果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。公式同样适用。因此,对于每个producto而不是7个操作,所有这些操作只有2个。经过这样的优化,你可能甚至不需要Cansel按钮。