• C# 开发excel addin插件的小积累


    好吧,进园子这么长时间了,第一次写博文,欢迎拍砖!

    关于excel的一些基本操作:

    1、引用

    开发excel插件,这两个引用是必不可少的。

    using Microsoft.Office.Interop.Excel;
    using Microsoft.Office.Tools.Ribbon;

    2、 工作簿、工作表、单元格的操作

    ApplicationClass application = new ApplicationClass(); //创建一个excel进程
    Workbook wbook = Globals.ThisAddIn.Application.ActiveWorkbook; //当前活动workbook
    Worksheet worksheet = (Worksheet)wbook.ActiveSheet; //当前活动sheet
    Range range = (Range)worksheet.Application.Selection;//当前选中的cells

    根据条件选择指定的sheet:

    Worksheet worksheet = wbook.Worksheets["sheet1"];//获取名为sheet1的工作表
    Worksheet worksheet = wbook.Worksheets[1];//获取第一个工作表

    其他的操作:

    workSheet.Range[workSheet.Cells[range.Row,1],workSheet.Cells[workSheet.UsedRange.Rows.Count,workSheet.UsedRange.Columns.Count]].Clear();//清除当前选定行以下的所有数据
    workSheet.UsedRange.Rows.Count//已使用的行数
    workSheet.UsedRange.Columns.Count//已使用的列数
    worksheet.Range["A1"].Font.ColorIndex = 3;//将“A1”单元格字体设为红色
    worksheet.Range["A1","B2"].Interior.ColorIndex = 3; //将“A1”到“B2”范围背景设为红色
    int num = wss1.Range[wss1.Cells[1, Y1]].Find("").Row; //第一次出现空单元格的行数
    worksheet.Cells["A1"].Rows.Hidden=true;//隐藏行
    worksheet.Cells["A1"].Columns.Hidden=true;//隐藏列
    View Code

    range与cells的区别不大,最重要的事range的范围比cells大;

    当然,用C#遍历所有单元格时若遇到空单元格,有可能会弹出“无法对null执行运行时绑定”,此时对单元格判断是否为空并用正则表达式匹配数字,然后比较大小的方法(将所有小于6的数字字体设为红色):

    1 string str = Convert.ToString(worksheet.Cells[i, j].value);
    2 string regex = @"^[1-9]d*|0$";
    3 if (str != null && Regex.IsMatch(str, regex))
    4 {
    5      if (Convert.ToDouble(str) < 6)
    6      {
    7         worksheet.Cells[i, j].Font.ColorIndex = 3;
    8      }
    9 }
    View Code

    3、 图表生成

    (1)以下是生成柱状图的方法(绑定数据的两种方法,一种是连续绑定数据,数据是连续的;另一种是部分绑定,数据是不连续的):

     1 wbook.Charts.Add(Type.Missing); //添加一個页面
     2 wbook.ActiveChart.ChartType = XlChartType.xlColumnClustered; //设置要显示的图表样式(簇状条形图)      
     3 Range rang = worksheet.get_Range(strx + "," + stry);
     4 wbook.ActiveChart.SetSourceData(rang, XlRowCol.xlColumns);//数据不连续
     5 //wbook.ActiveChart.SetSourceData(ws.Range["A1",ws.Cells[ws.UsedRange.Rows.Count,ws.UsedRange.Columns.Count]], XlRowCol.xlRows);//绑定数据,数据是连续的
     6 //wbook.ActiveChart.SetSourceData(ws.Range["A1","A40"], XlRowCol.xlColumns);//绑定数据,柱状图中图柱所代表的数据
     7 //没有这个标题就出不来
     8 wbook.ActiveChart.HasTitle = true;
     9 //设置绘图区的数据标志(就是线形顶上出现值)显示出值来
    10 wbook.ActiveChart.ApplyDataLabels(XlDataLabelsType.xlDataLabelsShowValue, false, false, false, false, false,true, false, false, false);
    11 //后面一坨也是有用的,例如要显示饼图的百分比,就必须将倒数第三个false改为true
    12 //设置Legend图例的位置和格式
    13 wbook.ActiveChart.HasLegend = true;
    14 wbook.ActiveChart.PlotArea.Width = 550; //设置绘图区宽度
    15 wbook.ActiveChart.PlotArea.Top = 30;
    16 wbook.ActiveChart.PlotArea.Height = 400; //设置绘图区高度
    17 wbook.ActiveChart.PlotArea.Left = 20;
    18 //表示图示画在SHEET1的,改成自己的SHEET名就好
    19 wbook.ActiveChart.Location(XlChartLocation.xlLocationAsObject, aimWorksheet.Name);
    20 //图形距离左上角的距离
    21 //wbook.ActiveSheet.ChartObjects.count //当前表中chart的数量
    22 wbook.ActiveChart.ChartArea.Top = (wbook.ActiveSheet.ChartObjects.count - 1) * 200 + wbook.ActiveSheet.ChartObjects.count * 20;
    23 wbook.ActiveChart.ChartArea.Left = 20;
    24 wbook.ActiveChart.ChartArea.Height = 200;
    25 wbook.ActiveChart.ChartArea.Width = 600;
    26 //x轴样式
    27 Axis xAxis = (Axis)wbook.ActiveChart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary);
    28 //y轴样式
    29 Axis yAxis = (Axis)wbook.ActiveChart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary);
    30 //  xAxis.CategoryNames = ws.Range["B2", ws.Cells[ws.UsedRange.Rows.Count, 2]];//x轴标注信息绑定
    31 xAxis.HasTitle = false;
    32 xAxis.TickLabels.Font.Name = "宋体";
    33 xAxis.TickLabels.Font.Size = 8;
    34 yAxis.TickLabels.NumberFormat = "##元"; //可以通过格式指定y轴的显示方式
    35 yAxis.TickLabels.Orientation = Microsoft.Office.Interop.Excel.XlTickLabelOrientation.xlTickLabelOrientationHorizontal;
    36 //Y轴显示的方向,是水平还是垂直等
    37 yAxis.TickLabels.Font.Size = 8;
    38 yAxis.TickLabels.Font.Name = "宋体";
    39  //设置标题和坐标轴
    40 wbook.ActiveChart.HasTitle = true;
    41 wbook.ActiveChart.ChartTitle.Text = str4+"柱状图"; //将默认标题改为指定标题
    42 wbook.ActiveChart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary).HasTitle = true;
    43 wbook.ActiveChart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary).AxisTitle.Characters.Text = str3;//在x轴上显示横坐标
    44 wbook.ActiveChart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary).HasTitle = true;
    45 wbook.ActiveChart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary).AxisTitle.Characters.Text = str4;//在y轴上显示纵坐标
    View Code

    当然生成图表并不是结束,我们还可以对其进行修改(下面是对当前选中的图表数据进行修改,try部分是为了如果是饼形图修改数据不会报错):

     1 Range rang = swsheet.get_Range(str1 + "," + str2);
     2 wbook.ActiveChart.SetSourceData(rang, XlRowCol.xlColumns);
     3 //设置标题和坐标轴
     4 wbook.ActiveChart.HasTitle = true;
     5 wbook.ActiveChart.ChartTitle.Text = comboBox4.SelectedItem + ""; //将默认标题改为指定标题
     6 try
     7 {
     8 wbook.ActiveChart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary).HasTitle = true;
     9 wbook.ActiveChart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary).AxisTitle.Characters.Text =
    10 comboBox5.SelectedItem.ToString(); //在x轴上显示横坐标
    11 wbook.ActiveChart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary).HasTitle = true;
    12 wbook.ActiveChart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary).AxisTitle.Characters.Text =
    13 comboBox1.SelectedItem.ToString(); //在y轴上显示纵坐标
    14 }
    15 catch (Exception exception)
    16 {
    17 }
    View Code

    还可以对图表的数据源进行筛选,筛选不是将无关数据删除,只是将其隐藏起来,隐藏数据的值和位置都是不变的:

    swsheet.Range["A1",swsheet.Cells[swsheet.UsedRange.Rows.Count, swsheet.UsedRange.Columns.Count]].AutoFilter(x, “>1”, XlAutoFilterOperator.xlAnd, Type.Missing, true); //筛选选定区域第x列所有大于1的数据
    wss1.Range[wss1.Cells[1, i], wss1.Cells[wss1.UsedRange.Rows.Count, i]].AdvancedFilter(XlFilterAction.xlFilterCopy, Type.Missing, wss1.Range["AZ1"], true);//将不重复数据写到Z列

    (2)数据透视表

    即水晶报表,将数据进行统计(下面进行多数据绑定中的两种方法:一个是pivotTable.AddFields可以绑定除数据求和项外的所有数据;若想求和项也绑定多数据,可以定义多个PivotField pivotField,因为一个sheet中只能有一个数据透视表):

     1 private void GeneratetPivot1(Worksheet worksheet, Workbook wbook, Worksheet wss1)
     2 {
     3 PivotCaches pivotCaches = wbook.PivotCaches();
     4 PivotCache pivotCache = pivotCaches.Add(XlPivotTableSourceType.xlDatabase, worksheet.UsedRange);//可选择数据绑定
     5 Range range = wss1.Range["A1", wss1.Cells[wss1.UsedRange.Rows.Count, wss1.UsedRange.Columns.Count]];//透视表起始位置
     6 //创建数据透视表
     7 PivotTable pivotTable = pivotCache.CreatePivotTable(range, wss1.Name, true,
     8 XlPivotTableVersionList.xlPivotTableVersionCurrent);
     9 pivotTable.AddFields("合同名称", Type.Missing, Type.Missing, true); //向数据透视表或数据透视图中添加行字段、列字段和页字段。
    10 pivotTable.AddFields(Type.Missing, Type.Missing,"季度",  true);
    11 pivotTable.AddFields( Type.Missing, "外协名称",Type.Missing, true);
    12 pivotTable.AddFields( Type.Missing, Type.Missing,"推广项目", true);
    13 PivotField pivotField;
    14 //PivotField pivotField2;
    15 // pivotField = (PivotField)pivotTable.PivotFields("季度"); //数据透视表的某一字段(左上)
    16 // pivotField.Orientation = XlPivotFieldOrientation.xlPageField;
    17 //pivotField = (PivotField)pivotTable.PivotFields("外协名称"); //数据透视表的某一字段(左上)
    18 // pivotField.Orientation = XlPivotFieldOrientation.xlPageField;
    19 //字段在指定的数据透视表中的位置xlHidden,xlRowField行,xlColumnField列,xlPageField筛选,xlDataField统计 
    20 //pivotField = (PivotField)pivotTable.PivotFields(7); //数据透视表的某一字段(右上)
    21 //pivotField.Orientation = XlPivotFieldOrientation.xlColumnField;
    22 //pivotField = (PivotField)pivotTable.PivotFields(8); //数据透视表的某一字段(左下)
    23 //pivotField.Orientation = XlPivotFieldOrientation.xlRowField;
    24 pivotField = (PivotField)pivotTable.PivotFields("供应商评估(十分制)"); //数据透视表的某一字段(右下)
    25 pivotField.Orientation = XlPivotFieldOrientation.xlDataField;
    26 pivotField.Function = XlConsolidationFunction.xlAverage; //返回或设置对数据透视表字段汇总时所使用的函数
    27 }
    View Code

    4、结束进程

    结束进程可以结束指定进程,也可以结束所有进程:

     1 private void KillExcelProceed()//结束所有进程
     2 {
     3 System.Diagnostics.Process[] ExcelProcesses;
     4 ExcelProcesses = System.Diagnostics.Process.GetProcessesByName("EXCEL");
     5 foreach (System.Diagnostics.Process IsProcedding in ExcelProcesses)
     6 {
     7       if (IsProcedding.ProcessName == "EXCEL")
     8       {
     9           IsProcedding.Kill();
    10       }
    11 }
    12 }
    13 [System.Runtime.InteropServices.DllImport("User32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    14 private static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
    15 private void Kill(Application excel)//结束指定excel进程
    16 {
    17 IntPtr t = new IntPtr(excel.Hwnd); //得到这个句柄,具体作用是得到这块内存入口 
    18 int k = 0;
    19 GetWindowThreadProcessId(t, out k); //得到唯一标志k
    20 System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k); //k的引用
    21 p.Kill(); //关闭k
    22 }
    View Code

    5、 数据写入

    数据写入也有两种方法:

    (1)第一种是直接写入,不过如果有空数据则有可能报错:

    wsheet1.Cells[i, j].value = wsheet2.Cells[x, y].value;

    (2)第二种是用copy函数将数据整体复制,相当于手动选择数据区域,复制到另一块区域:

     1 public static void CopyData(Worksheet worksheet, Worksheet sheetsource)
     2         {
     3             int src = sheetsource.UsedRange.Rows.Count;
     4             int scc = sheetsource.UsedRange.Columns.Count;
     5             int drc = worksheet.UsedRange.Rows.Count;
     6 
     7             Range range = sheetsource.Range[sheetsource.Cells[3, 1], sheetsource.Cells[src, scc]];
     8             range.Copy(Type.Missing);//复制数据
     9             Range range1 = worksheet.Range[worksheet.Cells[drc+1, 1], worksheet.Cells[drc + src-1, scc]];
    10             worksheet.Paste(range1, false);//粘贴数据
    11 
    12         }
    View Code

    (3)数据排序

    像第一种一条一条写入数据,有时可以将数据先排序然后导入,在特定时候可以节省很多不必要的操作,提高效率:

     1 int a = workSheet.UsedRange.Rows.Count;
     2 int b = workSheet.UsedRange.Columns.Count;
     3 Range myRange = (Range) workSheet.Cells[1, num];
     4 workSheet.Sort.SortFields.Clear();//清除绑定数据(不执行此操作则可能导致多次排序异常)
     5 workSheet.Sort.SortFields.Add(myRange,XlSortOn.xlSortOnValues,XlSortOrder.xlAscending,Type.Missing,XlSortDataOption.xlSortNormal);
     6 myRange = workSheet.Range[workSheet.Cells[1, 1], workSheet.Cells[a, b]];
     7 workSheet.Sort.SetRange(myRange);
     8 workSheet.Sort.Header = XlYesNoGuess.xlYes; //第一行或列是否包含头信息
     9 workSheet.Sort.MatchCase = false; //区分大小写
    10 workSheet.Sort.Orientation = XlSortOrientation.xlSortColumns; //行或列排序
    11 workSheet.Sort.SortMethod = XlSortMethod.xlPinYin; //英文或中文排序
    12 workSheet.Sort.Apply(); //执行排序
    View Code

    6、其他的一些操作

    触发事件和禁止触发事件:

    (1)触发事件(这是写在thisaddin_startup中的括号里面为触发函数,即当触发某一事件时,调用函数):

    1 Globals.ThisAddIn.Application.SheetSelectionChange += new Excel.AppEvents_SheetSelectionChangeEventHandler(Application_SheetSelectionChange);//点击单元格触发事件
    2 Globals.ThisAddIn.Application.SheetChange += new Excel.AppEvents_SheetChangeEventHandler(Application_SheetChange);//修改内容触发事件
    3 Globals.ThisAddIn.Application.SheetPivotTableUpdate += new Excel.AppEvents_SheetPivotTableUpdateEventHandler(Application_SheetPivotTableUpdate);//数据透视表更新触发事件
    4 Globals.ThisAddIn.Application.SheetCalculate += new Excel.AppEvents_SheetCalculateEventHandler(Application_SheetCalculate);//对工作表进行重新计算之后
    5 Globals.ThisAddIn.Application.SheetBeforeRightClick += new Excel.AppEvents_SheetBeforeRightClickEventHandler(Application_SheetBeforeRightClick); //右键单击工作表时触发事件
    6 Globals.ThisAddIn.Application.SheetFollowHyperlink+= new Excel.AppEvents_SheetFollowHyperlinkEventHandler(Application_SheetFollowHyperlink );//单击工作表上的任意超链接时
    7 Globals.ThisAddIn.Application.SheetActivate += new Excel.AppEvents_SheetActivateEventHandler(Application_SheetActivate);//激活工作表
    8 void Application_SheetSelectionChange(object sender, Excel.Range range){}//点击单元格触发事件函数
    9 void Application_SheetActivate(object sender){}//激活工作表函数
    View Code

    (2)禁止触发事件(触发事件是全局的,所以在特定时刻不需要触发事件时要将其禁止):

    1 Globals.ThisAddIn.Application.ScreenUpdating = false; //防止屏幕闪动
    2 Globals.ThisAddIn.Application.EnableEvents = false;//禁止触发事件
    3 Globals.ThisAddIn.Application.DisplayAlerts = false;//禁弹窗
    4 Globals.ThisAddIn.Application.DisplayAlerts = true;//启弹窗
    5 Globals.ThisAddIn.Application.ScreenUpdating = true; //启动屏幕闪动
    6 Globals.ThisAddIn.Application.EnableEvents = true;//启动触发事件
    View Code

    7、  错误

    (1)     在开发过程中,不可避免会出现一些bug和错误,调试运行的时候导致进程卡死的情况也有可能,次数多了,excel会自动禁用你调试出错的加载项。解决方法是:文件——选项,在弹出框最下方中间偏左下拉框选择“禁用项目”,点击“转到”,将被禁用的加载项启用,然后在“开发工具”选项卡点击“com加载项”,勾选你的项目名称,确定,加载项就出来了,又可以一起快乐的玩耍了!

    还有“异常来自 HRESULT:0x800A03EC”这种错误,一般是代码有错误,具体原因视情况而定。(已遇到因为从0开始循环抛异常和因为透视表表格格式不同而使用pivotField.PivotFilters.Add时抛异常)

    (2)     在卸载旧的addin时可能会未卸载干净,这就需要在注册表中删除,注册表位置:HKEY_CURRENT_USERSoftwareMicrosoftOfficeExcelAddins

    8、参考

    浅谈Excel开发:三 Excel 对象模型:

    http://www.cnblogs.com/yangecnu/p/3247234.html

    C#开发Excel报表系列整理:

    http://www.360doc.com/content/07/0824/10/12027_691547.shtml

    VSTO学习归结:

    http://club.excelhome.net/forum.php?mod=viewthread&tid=896478&extra=page%3D1

    工作簿工作表所有事件一览表:

    http://club.excelhome.net/thread-71744-1-1.html

  • 相关阅读:
    物联网平台推荐
    支持可视化看板和组态的物联网平台
    ThingsKit物联网平台物模型发布啦!!! ​​​
    基于ThingsBoard二次开发的物联网平台:ThingsKit物联网平台
    ThingsKit 物联网平台 v1.0.0 Release 版本发布
    ThingsKit:基于 Thingsboard 开发,面向中小型企业开箱即用的物联网平台。
    一文读懂 TDengine 的三种查询功能
    如何从 InfluxDB/OpenTSDB 无缝连接到 TDengine
    中智车联:用 TDengine 高效处理车辆运营可视化管理
    新一代开源时序数据库TDengine有哪些优势?
  • 原文地址:https://www.cnblogs.com/lx-bk/p/4166818.html
Copyright © 2020-2023  润新知