在我的帖子'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位版本'。我一直在编写以下代码来实现导出。
// 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)在活动的WorkSheet上创建表的标题,并定义XLSX文件的名称。 2)在_isAbsoluteChartDataBeingExported == true时,继续轮询ConcurrentQueue instanse以获取现有数据。 3)从ConcurrentQueue实例获取AGC_DataRecordToSave的当前实例(要导出的记录)。 4)从该AGC_DataRecordToSave实例中获取字段的值,并通过适当的单元格索引(cellIndex变量)将这些字段值设置为WorkSheet的单元格。 5)更正单元格的索引并再次轮询ConcurrentQueue实例以获取新记录。等等。当当前活动工作表上的行数达到限制(抛出COMException)时,转到下一张工作簿(使此列表激活)并再次重复2) - 5)项目。等等。当用户将导出到MS Excel时,将WorkBook(带有数据的表格)写入XLSX文件。但我无法达到预期的效果。以下是在MS Excel中看到结果的方法。
只有第一张表有数据。所有剩余的纸张都是空的。然而,正如您所看到的,已经存在不均匀的页面枚举(1,2,109,108,...)。但是表格的编号必须是以下(1,2,3,4,...)。我做错了什么?请帮我纠正并消除错误并让'exportToExcel'方法正常工作。
答案 0 :(得分:1)
有一种简单的方法可以使用npoi.mapper只有2行以下。并且它不需要在服务器上安装MS Office。
var mapper = new Mapper();
mapper.Save("test.xlsx", objects, "newSheet");