【发布时间】:2016-10-06 10:56:32
【问题描述】:
在“How to export DateTime, TimeSpan, string and double values to Excel from WPF MVVM application?”的帖子中,我询问了如何使用 VSTO 从 WPF MVVM 应用程序导出 MS Excel。不等答案,我决定自己试试。我的电脑上有“MS Excel 2016 MSO (16.0.4432.1000) 64-bite version”。我一直在编写以下代码来实现导出。
// 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) 当 _isAbsoluteChartDataBeingExported == true 时,继续轮询 ConcurrentQueue 实例以获取现有数据。 3) 从 ConcurrentQueue 实例中获取 AGC_DataRecordToSave 的当前实例(要导出的记录)。 4) 从此 AGC_DataRecordToSave 实例中获取字段值,并通过单元格的适当索引(cellIndex 变量)将这些字段值分配给 WorkSheet 的单元格。 5) 更正单元格的索引并再次轮询 ConcurrentQueue 实例以获取新记录。 ETC。当当前活动工作表上的行数达到限制(抛出 COMException)时,转到工作簿的下一个工作表(使此列表处于活动状态)并再次重复 2) - 5) 项。 ETC。当用户关闭导出到 MS Excel 时,将工作簿(带有数据表)写入 XLSX 文件。但我无法达到预期的效果。下面是结果在 MS Excel 中的显示方式。
而且只有第一张纸有数据。所有剩余的工作表都是空的。然而,正如您所看到的,不均匀的工作表枚举存在(1、2、109、108,...)。但是工作表的数量必须如下(1、2、3、4,...)。我做错了什么?请帮助我纠正和消除错误并让“exportToExcel”方法正常工作。
【问题讨论】:
标签: c# wpf excel export-to-excel