В моем посте в 'How to export DateTime, TimeSpan, string and double values to Excel from WPF MVVM application?' Я спрашиваю о том, как делать экспорт в MS Excel из приложения WPF MVVM, используя VSTO. Не дожидаясь ответа, я решил попробовать себя. У меня есть «MS Excel 2016 MSO (16.0.4432.1000) 64-бит версия» на моем компьютере. Я пишу следующий код для реализации экспорта.Ячейки в Excel._Worksheet неправильно заполнены данными
// Exports to MS Excel.
private async void exportToExcel()
{
await Task.Run(() =>
{
// Cell index.
int cellIndex = 2;
// MS Excel application instance.
Excel.Application oXL = null;
// Work book.
Excel._Workbook oWB;
// Active work sheet.
Excel._Worksheet oSheet;
// Cell range.
Excel.Range oRng;
// Next sheet index.
int sheetIndex = 2;
try
{
//Start Excel and get Application object.
oXL = new Excel.Application();
oXL.Visible = false;
//Get a new workbook.
oWB = oXL.Workbooks.Add(Missing.Value);
// Get shets quantity.
int sheetsQuantity = oWB.Sheets.Count;
// Get active sheet.
oSheet = (Excel._Worksheet)oWB.ActiveSheet;
//Add table headers going cell by cell.
oSheet.Cells[1, 1] = "Date";
oSheet.Cells[1, 2] = "Time";
oSheet.Cells[1, 3] = "Beam";
oSheet.Cells[1, 4] = "Direction";
oSheet.Cells[1, 5] = "Value";
//Format A1:E1 as bold, vertical alignment = center.
oSheet.get_Range("A1", "E1").Font.Bold = true;
oSheet.get_Range("A1", "E1").VerticalAlignment = Excel.XlVAlign.xlVAlignCenter;
// Get name of file to export to Excel.
string fileDateTime = DateTime.Now.ToString("dd.mm.yyyy hh:mm:ss");
fileDateTime = fileDateTime.Replace(".", "");
fileDateTime = fileDateTime.Replace(":", "");
fileDateTime = fileDateTime.Replace(' ', '_');
string fileName = "test_" + fileDateTime + ".xlsx";
// Exporting in Excel.
while (this._isAbsoluteChartDataBeingExported)
{
AGC_DataRecordToSave record;
if (this._agcAbsoluteDataRecordsToSaveBuf.TryDequeue(out record))
{
try
{
oSheet.Range["A" + cellIndex].Value = record.Date.ToString("d");
oSheet.Range["B" + cellIndex].Value = record.Time.ToString("T");
oSheet.Range["C" + cellIndex].Value = record.MeasuringBeam.ToString();
oSheet.Range["D" + cellIndex].Value = record.Direction;
oSheet.Range["E" + cellIndex].Value = record.Value;
}
catch(COMException)
{
//AutoFit columns A:E.
oRng = oSheet.get_Range("A1", "E1");
oRng.EntireColumn.AutoFit();
// If sheets number more than one.
if (sheetsQuantity > 1)
{
// If next sheet index is less than quantity of sheets then get next sheet and activate it.
if (sheetIndex < sheetsQuantity)
{
oSheet = oWB.Sheets[sheetIndex];
oSheet.Activate();
sheetIndex += 1;
cellIndex = 2;
//Add table headers going cell by cell.
oSheet.Cells[1, 1] = "Date";
oSheet.Cells[1, 2] = "Time";
oSheet.Cells[1, 3] = "Beam";
oSheet.Cells[1, 4] = "Direction";
oSheet.Cells[1, 5] = "Value";
//Format A1:E1 as bold, vertical alignment = center.
oSheet.get_Range("A1", "E1").Font.Bold = true;
oSheet.get_Range("A1", "E1").VerticalAlignment = Excel.XlVAlign.xlVAlignCenter;
continue;
}
else
{
// Else, add new sheet in workbook.
oWB.Sheets.Add(Missing.Value, oSheet, 1, Excel.XlSheetType.xlWorksheet);
oSheet = oWB.Sheets[2];
oSheet.Visible = Excel.XlSheetVisibility.xlSheetHidden;
sheetsQuantity += 1;
sheetIndex += 1;
cellIndex = 2;
//Add table headers going cell by cell.
oSheet.Cells[1, 1] = "Date";
oSheet.Cells[1, 2] = "Time";
oSheet.Cells[1, 3] = "Beam";
oSheet.Cells[1, 4] = "Direction";
oSheet.Cells[1, 5] = "Value";
//Format A1:E1 as bold, vertical alignment = center.
oSheet.get_Range("A1", "E1").Font.Bold = true;
oSheet.get_Range("A1", "E1").VerticalAlignment = Excel.XlVAlign.xlVAlignCenter;
continue;
}
}
else
{
// Else, add new sheet in workbook.
oWB.Sheets.Add(Missing.Value, oSheet, 1, Excel.XlSheetType.xlWorksheet);
oSheet = oWB.Sheets[2];
oSheet.Visible = Excel.XlSheetVisibility.xlSheetHidden;
sheetsQuantity += 1;
sheetIndex += 1;
cellIndex = 2;
//Add table headers going cell by cell.
oSheet.Cells[1, 1] = "Date";
oSheet.Cells[1, 2] = "Time";
oSheet.Cells[1, 3] = "Beam";
oSheet.Cells[1, 4] = "Direction";
oSheet.Cells[1, 5] = "Value";
//Format A1:E1 as bold, vertical alignment = center.
oSheet.get_Range("A1", "E1").Font.Bold = true;
oSheet.get_Range("A1", "E1").VerticalAlignment = Excel.XlVAlign.xlVAlignCenter;
continue;
}
}
}
cellIndex++;
}
// Save work book in XLSX-file.
if (!File.Exists(Path.Combine(this.PathToCsvRepository, fileName)))
oWB.SaveAs(Path.Combine(this.PathToCsvRepository, fileName), Missing.Value, Missing.Value, Missing.Value, true, true, Excel.XlSaveAsAccessMode.xlNoChange,
Excel.XlSaveConflictResolution.xlLocalSessionChanges, Missing.Value, Missing.Value, Missing.Value, true);
}
catch (IOException ex)
{
string errorMessage = string.Empty;
errorMessage = string.Concat(errorMessage, ex.Message);
errorMessage = string.Concat(errorMessage, " Line: ");
errorMessage = string.Concat(errorMessage, ex.Source);
MessageBox.Show(errorMessage, "Ошибка");
}
catch (Exception ex)
{
string errorMessage = string.Empty;
errorMessage = string.Concat(errorMessage, ex.Message);
errorMessage = string.Concat(errorMessage, " Line: ");
errorMessage = string.Concat(errorMessage, ex.Source);
MessageBox.Show(errorMessage, "Ошибка");
}
finally
{
// Complete work with Excel.
CloseExcel(oXL);
}
});
}
Где _agcAbsoluteDataRecordsToSaveBuf является ConcurrentQueue экземпляра и _isAbsoluteChartDataBeingExported является логическим флагом, который устанавливается, когда пользователь поворачивает на экспорт в MS Excel и снят с охраной, когда пользователь выключает этот экспорт. И ниже метод закрытия Excel:
// Closes Excel.
private static void CloseExcel(Excel.Application theApp)
{
int id = 0;
IntPtr intptr = new IntPtr(theApp.Hwnd);
System.Diagnostics.Process p = null;
try
{
GetWindowThreadProcessId(intptr, out id);
p = System.Diagnostics.Process.GetProcessById(id);
if (p != null)
{
p.Kill();
p.Dispose();
}
}
catch (Exception ex)
{
MessageBox.Show("CloseExcel:" + ex.Message);
}
}
Что мне нужно: 1) Создать заголовок для таблицы на активном листе и определяют имя XLSX-файл. 2) Проведите одновременное опробование ConcurrentQueue для существующих данных, тогда как _isAbsoluteChartDataBeingExported == true. 3) Возьмите текущий экземпляр AGC_DataRecordToSave (запись для экспорта) из экземпляра ConcurrentQueue. 4) Возьмите значения полей из этого экземпляра AGC_DataRecordToSave и присвойте эти значения поля ячейкам WorkSheet соответствующим индексом для ячеек (переменная cellIndex). 5) Исправьте индекс для ячеек и опросите экземпляр ConcurrentQueue снова для новой записи. И т.д. Когда количество строк на текущем активном листе достигает предела (вызывается COMException), перейдите к следующему листу WorkBook (сделайте этот список активным) и повторите снова 2) - 5). И т.д. Когда пользователь превращает экспорт в MS Excel, вы можете записать WorkBook (с листами с данными) в XLSX-файл. Но я не могу добиться желаемого эффекта. Ниже приведен пример результата в MS Excel.
И только первый лист имеет данные. Все остальные листы пусты. И все же, как вы видите, неравномерное перечисление листов имеет место (1, 2, 109, 108, ...). Но нумерация листов должна быть следующей (1, 2, 3, 4, ...). Что я делаю неправильно? Пожалуйста, помогите мне исправить ошибки и устранить их и получить метод «exportToExcel» для правильной работы.
Я прошу прощения, ДонниТиан, но я не спрашиваю о том, какая библиотека лучше, я спросил, что должен сделать в своем коде, чтобы получить правильный результат. – Prohor