C#.net实现windows窗体程序对Excel文件的读写操作
1 C#操作excel文件
1.1 C#调用excel控件
首先要保证机器已经安装了Office,并安装了Excel。然后按以下步骤进行:
1)在项目中添加引用;
2)在com标签页中,找到“Microsoft Excel 11.0 Object Library”添加进来;
3)在后台cs类中,引入一下命名空间:
代码:
using Microsoft.Office.Interop.Excel; using ExcelApplication = Microsoft.Office.Interop.Excel.Application; using System.Reflection; using System.IO; /* 读写Excel form需要添加引用 Excel COM。 * 1 右击项目,点击添加引用。 * 2 选择COM选项卡,添加Microsoft Excel 11.0 Object Library。 * 3 在文件中添加命名空间 using Microsoft.Office.Interop.Excel;和using ExcelApplication = Microsoft.Office.Interop.Excel.Application; */ /* 命名空间using System.Reflection;用于ApplicationClass.Workbooks.Open()中的Missing.Value。 * Missing.Value的作用是使用COM组件时,填充不需要的参数位。 */
1.2 读excel文件
代码:
public void LoadStuffExcel() { string fileName=fileStuffExcel; if (File.Exists(@fileName) == false) { MessageBox.Show(fileName + "不存在,请检查"); return; } ApplicationClass mApp = new ApplicationClass(); mApp.Visible = false; // Excel不显示 Workbook mBook = mApp.Workbooks.Open(fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value); Worksheet mSheet = mBook.Worksheets[1] as Worksheet; Range mRange = mSheet.get_Range("A1", "E11"); rowNum = mRange.Rows.Count; colNum = mRange.Columns.Count; /* Array类型是所有数组类的父类。本程序中主要用到以下几个属性 * System.Array.GetLength(int):获取一个 32 位整数,该整数表示 System.Array 的指定维中的元素数。 * System.Array.GetValue(int, int):获取二维 System.Array 中指定位置的值。索引指定为 32 位整数。 * 注意GetValue(int,int)中,下标的用法和普通下标用法不同。请见下面的说明。 * 这里mArray依然是一个二维数组,只不过类型为Array。而不是普通的string[,]。 */ mArray = mRange.Formula as Array; mBook.Close(false, null, null); mApp.Quit(); mRange = null; mSheet = null; mBook = null; mApp = null; GC.Collect(); }
1.3 写excel文件
代码:
1.4 关闭excel文件
代码:
2 datagridview的操作
2.1 datagridview显示数据
Datagridview有一个属性卫datasource,使用datasource的方式加载数据到datagridview中速度快,逻辑清晰。
Herbert已经对Datagridview 的datasource做了一个总结:http://www.cnblogs.com/herbert/archive/2010/08/25/1808381.html
但是本文没有使用datasource的方式,而是直接添加行的方式在填充datagridveiw控件。之所以不使用datasource是因为使用该方式会带来排序的问题。例如,datagridview有一列为序号,那么点击列头,会有一个自动排序的效果,假设有1~10行数据,该效果的默认排序结果为1,10,2,3,4,5,6,7,8,9。显然与我们排序的初衷不符。而使用datasource的方式加载数据无法对该排序进行微调。Symon查找了大量文章,都未找到合适的解决方法。如果有大虾知道怎样解决datasource方式datagridview排序的问题,希望能够赐教,谢谢。
最后采取直接添加行,然后重写排序函数的方式来解决该排序问题。
排序函数代码:
public MainForm() { InitializeComponent(); LoadStuffExcel(); LoadListBinary(); dataGridView1.SortCompare += new DataGridViewSortCompareEventHandler(this.dataGridView1_SortCompare);//重载排序函数 dataGridView2.SortCompare += new DataGridViewSortCompareEventHandler(this.dataGridView1_SortCompare); PopulateDataGridView(); label1.Text = "所有工作人员共" + (rowNum - 1).ToString() + "人"; label2.Text = "已选工作人员共0人"; } private void dataGridView1_SortCompare(object sender, DataGridViewSortCompareEventArgs e)//排序函数 { /* if (e.Column.Name != mArray.GetValue(1, 2).ToString() && e.Column.Name != mArray.GetValue(1, 5).ToString()) { e.SortResult = Convert.ToInt16(e.CellValue1).CompareTo(Convert.ToInt16(e.CellValue2)); } else { e.SortResult = System.String.Compare(e.CellValue1.ToString(), e.CellValue2.ToString()); } if (e.SortResult == 0 && e.Column.Name != "ID") { e.SortResult = System.String.Compare( dataGridView1.Rows[e.RowIndex1].Cells["ID"].Value.ToString(), dataGridView1.Rows[e.RowIndex2].Cells["ID"].Value.ToString()); }*/ // Try to sort based on the cells in the current column. int tmp; if (int.TryParse(e.CellValue1.ToString(),out tmp)) { e.SortResult = Convert.ToInt16(e.CellValue1).CompareTo(Convert.ToInt16(e.CellValue2)); if (e.SortResult == 0 && e.Column.Name != dataGridView1.Columns[0].Name) { e.SortResult = Convert.ToInt16(dataGridView1.Rows[e.RowIndex1].Cells[0].Value.ToString()).CompareTo(Convert.ToInt16(dataGridView1.Rows[e.RowIndex2].Cells[0].Value.ToString())); } } else { e.SortResult = System.String.Compare(e.CellValue1.ToString(), e.CellValue2.ToString()); if (e.SortResult == 0 && e.Column.Name != dataGridView1.Columns[0].Name) { e.SortResult = Convert.ToInt16(dataGridView1.Rows[e.RowIndex1].Cells[0].Value.ToString()).CompareTo(Convert.ToInt16(dataGridView1.Rows[e.RowIndex2].Cells[0].Value.ToString())); } } e.Handled = true; }
2.2 两个datagridview间的数据copy
代码:
private void addStuff_Click(object sender, EventArgs e) { int numItem = dataGridView1.SelectedRows.Count; if (numItem == 0) { MessageBox.Show("请选择表单左侧的行选项来选择要添加的工作人员"); return; } //防止加载顺序颠倒。 for (int i = numItem - 1; i >= 0; i--) { string[] newRow = new string[colNum]; for (int j = 0; j < colNum; j++) { newRow[j] = dataGridView1.SelectedRows[i].Cells[j].Value.ToString(); } dataGridView2.Rows.Add(newRow); } label2.Text = "已选工作人员共" + dataGridView2.Rows.Count + "人"; }
GC.Collect();非常重要,强制垃圾回收,否则会导致在进程管理器中excel.exe驻留。但是网上也有朋友说使用GC.Collect()无法彻底解决该问题。Symon没有遇到过,但可以保证按上述示例代码,每一个声明过的变量最后都赋为null并且加上GC.Collect(),肯定可以消除excel.exe在进程中的驻留问题。