Исключение COM-исключения Excel во время работы в фоновом режиме
Я пытаюсь применить некоторые стили к ячейкам в своей книге. И я хочу сделать это в фоновом потоке, чтобы мой графический интерфейс мог оставаться отзывчивым. Эта работа займет несколько секунд, и если я нажму на какую-то случайную ячейку в моем документе, я получу исключение. Вот мой код:
public void ApplyStyles() { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += DoWork; bw.RunWorkerAsync(); } private void DoWork(object sender, DoWorkEventArgs e) { try { foreach (ICell xcell in cells) { Microsoft.Office.Interop.Excel.Range cell = cellUtility.GetCell(xcell); if (styles.ContainsKey(styleIds[xcell.Style])) { Style s = styles[xcell.Style]; cell.Style = s; } } } catch (Exception ex) { if (Logger.IsErrorEnabled) { Logger.Error(ex.ToString()); } messageBox.ShowErrorMessage(localizationMessages.ApplyingErrorText, localizationMessages.ApplyingErrorCaption); } }
Когда происходит исключение, это сообщение, которое я получаю;
System.Runtime.InteropServices.COMException (0x800AC472): Exception from HRESULT: 0x800AC472 at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData) at Microsoft.Office.Interop.Excel.Range.set_Style(Object value) at ABZ.ReportFactory.OfficeAddin.Excel.BatchLinking.BackgroundStyleApplier.DoWork() in C:\ABZ\ABZ ReportFactory Office Addin\ABZ.ReportFactory.OfficeAddin.Excel\BatchLinking\BackgroundStyleApplier.cs:line 86
Можно ли сделать этот стиль, применяя операцию в фоновом потоке? И как мне это сделать?
- Создание файла xls со слишком большим количеством листов с использованием Microsoft.Office.Interop.Excel
- c # Excel Interop, Определить, когда вставлен столбец или строка
- Получить экземпляр приложения Excel с помощью C # с помощью Handle
- Получение справки рабочего листа Excel по имени рабочего листа через C #
- Чтение текстового формата из Excel с помощью Microsoft.Office.Interop.Excel
Вторая проблема заключается в том, что, хотя этот стиль применяется в фоновом режиме, мой курсор постоянно меняет состояние от занятого до регулярного, пока эта операция не закончится. Я бы хотел, чтобы курсор был нормальным. Этот пользователь полностью не знает об этой фоновой операции.
приветствия, Владимир
- Не удается запустить диалог «Хотите сохранить изменения» в Excel
- Обновление внешней системы от excel
- C # Экспортировать диаграмму Excel как объект (а не как изображение) в Word
- Рабочий стол Excel Interop HRESULT: 0x800A03EC с использованием VB.net
- Как добавить текстовое поле в определенную позицию в ExcelSheet?
- Замораживание панелей в нескольких листах C #
- C #, Microsoft interop, проблема Excel numberformat
- Office 2007 PIA
Вы должны быть уверены, что получите корневой объект приложения Excel, а оттуда – диапазон, из потока, в котором выполняется работа. Все объекты Excel COM живут в однопоточной квартире (STA), поэтому вы не можете просто использовать их из какого-либо другого потока.
Вы не показываете, как «cellUtility.GetCell» фактически получает диапазон, но вероятная проблема заключается в том, что вы используете объект приложения, который изначально был извлечен из другого потока.
Выполнение такого рода работы в «фоновом потоке, так что ваш графический интерфейс может оставаться отзывчивым» проблематично – вся работа в Excel в конечном итоге происходит в основном потоке Excel, поскольку Excel (по существу) однопоточен.
Есть несколько способов приблизиться к этому:
-
Часто вы обнаружите, что отключение ScreenUpdating и настройка Calculation to Manual позволяют выполнять работу по редактированию намного быстрее, тогда вам не нужны другие темы или что-то еще.
-
Запустите свою работу над основным потоком, но разбейте его на небольшие куски, а затем запланируйте следующий фрагмент, который нужно выполнить после ввода в Excel – вы можете создать Windows.Forms.Timer или если вы можете использовать макрос Excel, используйте Application.OnTime для запланируйте следующую часть работы.
-
Если вы хотите выполнить работу из другого потока, вам нужно получить объект Application и еще один COM-объект в этом потоке. Может оказаться сложным получить правильный экземпляр Excel, но Эндрю Уайтчепел описывает хороший подход здесь: http://blogs.officezealot.com/whitechapel/archive/2005/04/10/4514.aspx . Тем не менее, вам все равно придется проверять наличие ошибок на каждом COM-вызове из другого потока, поскольку Excel может быть занят и может отклонить любой COM-вызов из другого потока в любой момент (особенно если ваши пользователи взаимодействуют с этим «гибким графическим интерфейсом». необходимо, по крайней мере, проверить COMExceptions с ошибками – каждый COM-вызов может вызывать одно из следующих:
- const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
- const uint VBA_E_IGNORE = 0x800AC472;
Excel_DNA (библиотека интеграции Excel / .NET, которую я разрабатываю) предоставляет доступ к объекту приложения в потоке, который вы запускаете, вызывая ExcelDnaUtil.Application. Но я по-прежнему рекомендую перемещать все взаимодействия с объектной моделью Excel в основной поток Excel, возможно, используя вызов Application.Run для запуска команды tell Excel для запуска макроса. Затем вызов Application.Run становится единственной точкой, где COMException можно проверить и повторить из вашего фонового потока.