之所以基于 Excel 开发插件,一个重要的原因就是 Excel 在数据展示、分析和处理的灵活性。本篇实现从数据库中基于 SQL 将数据导入到 Excel 工作表。
按照上一篇介绍的操作方法创建一个 Excel VSTO Add-In 项目,添加一个 Ribbon,从工具箱中拖入一个 Button 控件,Label 属性设置为 Import Data。完成后 Ribbon 的界面如下:
实现从数据库中获取数据
考虑到 MS Access 是微软数据库,Visual Studio 天然支持,本例的数据库使用 MS Access 数据库。从数据库导入的数据,可以用 IList<> 来存储,也可以用 ADO.Net 的 DataTable 数据类型来存储,用 DataTable 比较灵活,所以我们用 DataTable 来实现。下面的代码基于 ADO.Net,因为 ADO.Net 的使用不是本篇的重点,代码不做说明。
using System.Data;
using System.Data.OleDb;
namespace VSTODemo {
public class EmployeeService {
private static OleDbConnection conn = null;
public static OleDbConnection GetConnection() {
string connStr = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\my-documents\Sample Database\Employees.accdb";
var conn = new OleDbConnection(connStr);
return conn;
}
public static DataTable ListAll() {
var conn = EmployeeService.GetConnection();
string selectCmd = "select * from employees";
OleDbDataAdapter adapter = new OleDbDataAdapter(selectCmd, conn);
DataTable employees = new DataTable();
adapter.Fill(employees);
return employees;
}
}
}
数据导入工作表
基于 Excel 对象模型将输入导入也是很模式化的代码,我编写了一段通用代码来实现:
using Microsoft.Office.Interop.Excel;
using System;
namespace VSTODemo {
public class ExcelUtils {
public static void CopyFromDataTable(System.Data.DataTable dt, Worksheet sht) {
if (dt == null) return;
int colCount = dt.Columns.Count; // 列数量
int rowCount = dt.Rows.Count; // 行数量
if (colCount == 0 || rowCount == 0) {
throw new Exception("Empty table!");
}
// Header array
object[] headerArray = new object[colCount];
for (int col = 0; col < colCount; col++) {
headerArray[col] = dt.Columns[col].ColumnName;
}
Range startCell = (Range)sht.Cells[1, 1]; // 从第一行第一列开始
// Write header from header array
Range headerRange = sht.get_Range(startCell, (Range)sht.Cells[startCell.Row, colCount]);
headerRange.Value = headerArray;
// Value for line item Cells
object[,] valueArray = new object[rowCount, colCount];
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < colCount; col++) {
valueArray[row, col] = dt.Rows[row][col];
}
}
// 数据整体从array拷贝到工作表(从表头的下一行开始)
sht.get_Range(startCell.Offset[1, 0], (Range)(sht.Cells[rowCount + 1, colCount])).Value = valueArray;
}
}
}
在 Button_click 事件中编写导入的代码:
using Microsoft.Office.Interop.Excel;
using Microsoft.Office.Tools.Ribbon;
namespace VSTODemo {
public partial class Ribbon1 {
private Application excelApp;
private void Ribbon1_Load(object sender, RibbonUIEventArgs e) {
excelApp = Globals.ThisAddIn.Application;
}
private void btnImport_Click(object sender, RibbonControlEventArgs e) {
System.Data.DataTable employees = EmployeeService.ListAll();
Worksheet activeSheet = excelApp.ActiveSheet;
ExcelUtils.CopyFromDataTable(employees, activeSheet);
}
}
}