你的位置:首页 > ASP.net教程

[ASP.net教程]实现标记datagridview标题并导出Excel的功能


最近在学习winform,国庆前被布置了一个小任务,好不容易大致做出来了,决定记录下来,以此加深印象。

先说下需求:这是一个导入话单标记后并导出的功能

1. 选择excel文件

2. 定义字段
   日期 时间 对方号码 通话时长 呼叫类型
3. 点击datagridview 标题 出现下拉菜单 显示定义的字段
4. 标记定义字段列
5. 保存定义字段数据 到 datatable
6  导出datatable

按照需求一步一步来,先设计界面,需要一个DataGridView和两个Button,一个导入,一个导出,我加了个Label和TextBox来提示文件路径。

先在类里面定义几个全局变量,下面的代码中会用到。

1     int colIndex;//点击的单元格列索引2     int rowIndex;//点击的单元格行索引   3     Dictionary<int, string> dic = new Dictionary<int, string>();//存放excel标题4     List<string> list = new List<string>();  //存放标记后的标题5     DataTable dt;//导入的table6     string filename = "";//Excel文件名

View Code

第一步:导入Excel预览,我从网上找了一段excel导入datagridview的代码,具体如下:

 1     private DataTable ExcelToDataTable(string path) 2     { 3  4       FileStream fs = File.OpenRead(path);  //打开.xls文件 5  6       HSSFWorkbook wk = new HSSFWorkbook(fs);  //把xls文件中的数据写入wk中 7  8       var sheet = wk.GetSheetAt(0);  //提取第一个sheet 9       var headerRow = sheet.GetRow(0);//提取sheet第一行10       var cellCount = headerRow.LastCellNum;//提取行的最后一列11       DataTable table = new DataTable();12       //给table添加一个列13       for (int i = headerRow.FirstCellNum; i < cellCount; i++)14       {15         DataColumn col = new DataColumn(headerRow.GetCell(i).StringCellValue);16         table.Columns.Add(col);17       }18       //获取sheet的行数19       var rowCount = sheet.LastRowNum;20       //循环逐行将sheet中数据写入table21       for (int i = (sheet.FirstRowNum + 1); i < rowCount; i++)22       {23         var row = sheet.GetRow(i);24         DataRow datarow = table.NewRow();25         for (int j = row.FirstCellNum; j < cellCount; j++)26         {27           if (row.GetCell(j) != null)28           {29             datarow[j] = row.GetCell(j).ToString();30           }31         }32         table.Rows.Add(datarow);33       }34       wk = null;35       sheet = null;36       return table;37     }

导入方法

这是个导入的方法,双击导入按钮,在事件里添加如下代码:

 1     private void btnImport_Click(object sender, EventArgs e) 2     { 3       OpenFileDialog ofd = new OpenFileDialog(); 4       ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); 5       ofd.Filter = "Excel Files(*.xls)|*.xls"; 6       if (ofd.ShowDialog() != DialogResult.OK) 7       { return; } 8       filename = ofd.FileName; 9       textBox1.Text = ofd.FileName;10       dt = ExcelToDataTable(filename);11       dataGridView1.DataSource = dt;//ExcelToDataTable(ofd.FileName);12 13       int ColCount = dataGridView1.Columns.Count;14       //将Excel所有标题存入dic中15       for (int i = 0; i < ColCount; i++)16       {17         dic.Add(i, dataGridView1.Columns[i].HeaderText);18       }19     }

导入预览

为了方便我将测试的Excel文档放到桌面,Excel的标题我存到了字典里,下面会用到。

到这里基本实现了第一步,点击导入按钮,选中excel文件,显示在datagridview上预览。

 

第二步、第三步:要求的样式大概是这样:

点击datagridview的标题,弹出下拉菜单,显示定义的字段。因此添加一个ContextMenuStrip控件,将字段一个个添加进去。

要求点击标题弹出下拉菜单,我用到了datagridview的CellCilck事件,这个事件里代码非常简单,只要弹出contexmenustrip就行了,然后加一个对是否为标题行的判断。

View Code

第四步比较复杂,大概思路是,下拉菜单的选项是固定的,通过contextMenuStrip1_ItemClicked事件里的e.ItemClicked.Text可以获取到你选择的菜单,因此我用了switch case语句来进行判断。

首先是点击datagridview一列的标题,然后选中一个菜单,这一列的标题要变成e.itemClicked,并且标记这一列,所以我写了一个标记的方法表示标记后操作和样式。

1     private void Mark(string item)2     {3       dt.Columns[colIndex].ColumnName = item;4       dataGridView1.Columns[colIndex].HeaderText = item;5       dataGridView1.Columns[colIndex].DefaultCellStyle.BackColor = Color.LightSteelBlue;6       dataGridView1.EnableHeadersVisualStyles = false;7       dataGridView1.Columns[colIndex].HeaderCell.Style.BackColor = Color.LightSlateGray;8     }

Mark

因为涉及到匹配的问题,例如日期格式的列无法标记成“呼叫类型”,“通话时间”等,所以加了一些正则判断,正则表达式以前从没用过,也是网上现学的,写得比较差。

又写了一个判断后的方法:

 1 private void MatchItem(string match, string str, string item) 2     { 3       Match m = Regex.Match(match, str); 4       if (m.Success) 5       { 6         Mark(item); 7         //如果该列已标记,则不添加item到list 8         foreach (var i in list) 9         {10           if (item == i)11             return;12         }13         list.Add(item);14       }15       else16       {17         contextMenuStrip1.Hide();18         MessageBox.Show("该列不为" + item + "!");19       }20     }

判断格式

至于contextmenustrip_itemClicked事件里只要在每个case里调用MatchItem方法就可以了。

 1  private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e) 2     { 3       //dt = ExcelToDataTable(filename); 4       //获取想要标记的的标题 5       string item = e.ClickedItem.Text; 6       //获取用于判断的内容 7       var BeMatch = dataGridView1.Rows[rowIndex + 1].Cells[colIndex].Value.ToString(); 8       //当前列在table是否已经存在 9       int i = 0;10       foreach (DataColumn dataCol in dt.Columns)11       {12         if (i != colIndex && dataCol.ColumnName == item)13         {14           contextMenuStrip1.Hide();15           var index = i + 1;16           MessageBox.Show("该表第" + index + "列为" + dataCol.ColumnName + ",无法标记");17           return;18         }19         i++;20       }21 22       switch (item)23       {24         case "呼叫类型":25           {26             string strType = @"[\u4e00-\u9fbb]";27             MatchItem(BeMatch, strType, item);28           }29           break;30         case "对方号码":31           {32             string strNum = @"0?[1]+[358]+\d{9}";33             MatchItem(BeMatch, strNum, item);34           }35           break;36         case "日期":37           {38             string strDate = @"^2\d{7}$";39             MatchItem(BeMatch, strDate, item);40           }41           break;42         case "时间":43           {44             string strTime = @"^[0-2]\d{1}[0-5]\d{1}[0-5]\d{1}$";45             MatchItem(BeMatch, strTime, item);46           }47           break;48         case "通话时长":49           {50             string strOften = @"\d";51             MatchItem(BeMatch, strOften, item);52           }53           break;54         case "取消设置":55           {56             //遍历原标题,获取取消设置的列,移出dt57             foreach (var kv in dic)58             {59               if (kv.Key == colIndex)60               {61                 list.Remove(dataGridView1.Columns[colIndex].HeaderText);62                 //list.Insert(colIndex,kv.Value);63                 item = kv.Value;64                 dt.Columns[colIndex].ColumnName = item;65               }66             }67             //还原标题和样式          68             dataGridView1.Columns[colIndex].DefaultCellStyle.BackColor = Color.White;69             dataGridView1.Columns[colIndex].HeaderCell.Style.BackColor = DefaultBackColor;70           }71           break;72       }73     }

标记列

第五步 :保存标记后的字段数据到datatable里,我在网上找了一个方法,附上链接:http://www.jb51.net/article/80620.htm

 1  private void btnExport_Click(object sender, EventArgs e) 2     { 3       //添加标记的列到table 4       DataTable table = dt.DefaultView.ToTable(false, list.ToArray()); 5  6       try 7       { 8         SaveFileDialog sfd = new SaveFileDialog(); 9         //sfd.FileName = "测试导出.xls";10         sfd.Filter = "Excel Files(*.xls)|*.xls";11         sfd.FileName = "测试导出";12         if (sfd.ShowDialog() == DialogResult.OK)13         {14           filename = sfd.FileName;15           DataToExcel(table, filename, "话单", false);16         }17       }18       catch (Exception ex)19       {20         MessageBox.Show(ex.Message);21       }

导出标记后的列

做完运行的效果是这样的:


 

到这里基本结束了,运行后没什么大问题,可能有的bug还没有测出来。第一次写博客,写的不好大家见谅,欢迎提出各种意见和建议。谢谢支持!