如何在Word中实现Excel图表刷新

在word2003的时代,word中图表的实现,还是通过MSChart(如图1)来实现的,该图表控件在word中是OLE COM对象,是以out-process的方式进行工作。在VSTO中可以对其进行直接操作。但MSChart的图表对象确实在样式和美观上远不及word2007之后的excel图表。如图2,MSChart图表的样式。

figure 1. 添加MSChart对象

figure 2. MSChart图表样式

 

当然要是word2007中的图表,就必须要求office的版本在2007或更高。但是安装了office2007后,使用VS2008创建word2007插件,貌似还不能实现excel图表的操作,无论怎么找也找不到Chart相关的接口。 原来PIA 2007中Microsoft.Office.Interop.Word.dll好像没有这部分接口(如图3)。是否通过VSTO就无法操作excel图表来吗?默认在VS2008中新建的WORD2007插件项目中,引用的Microsoft.Office.Interop.Word.dll是微软官方PIA提供的dll文件,如图4.

figure 3.PIA 2007 中Microsoft.Office.Interop.Word.dll部分接口

figure 4. 默认引用pia的dll文件

PIA是Primary Interop Assemblies的简称,它是由微软提供的接口组件,其中包含了COM接口的类型定义,方法签名等。它是.net操作COM的一种实现方式--—COM Interop。而PIA是微软官方提供了一套操作WORD的COM接口,只是貌似漏了一些接口而已。无论是官方还是非官方提供的接口,要想实现COM接口,客户机必须依据注册了该COM对象,否则也无法使用。一般只有客户机安装了office,那么就已经注册了Office的相关COM对象,如Excel,Word等。我们可以通过引用COM的方式,来让VS2008帮我们生成COM的接口签名,如图添加Microsoft Word 14.0 Object Library,由于本机安装的是office2010,因此就没有Microsoft Word 12.0 Object Library。

figure 5. 添加Microsoft Word 14.0 Object Library COM 引用
添加完COM引用后,在项目的引用列表中出现了Microsoft.Office.Interop.Word.dll和默认的PIA引用名称是一样的,但属性却有很大不同。如图6
 
figure 6. Microsoft Word 14.0 Object Library COM 引用的属性

这是因为VS2008生成的Interop是放在GAC中的,并且版本号也与PIA有很大不同。最重要的是,该dll中包含了Chart相关接口。如图7.

figure 7.  Microsoft Word 14.0 Object Library 接口

有了这些接口,操作Excel图表就没有问题了,因为由于操作的是excel图表,图表的数据是存储在excel中的,因此也需要将excel的com或PIA引用进WORD插件项目中,这样就可以方便的操作excel中的数据了。另外如果您觉得引用COM不方便,或者没有安装office2007而安装的是office2010的话,您可以自己编写Interop,并指需要实现Chart相关的接口接口。如果您觉得还是比较麻烦,那么你可以使用项目默认的pia,然后下载我编写好的Interop(http://code.google.com/p/interopword/),该Interop只包含了Chart相关的接口。

Demo

新建ChartDemo,Word2007插件项目,添加Interop.Word.dll引用和Excel,PIA引用。添加菜单中添加一个按钮,用于触发更新图表事件。项目如图8.

figure 8. Solution.
在ThisAddIn.cs文件中添加代码,用于构建菜单:

protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject() {
    return new Ribbon();
}

核心代码,用于更新图表数据:

public void btnUpdate_Click(Office.IRibbonControl sender) {
            UpdateCharts();
        }

        private void UpdateCharts() {
            ExcelProcessManager pm = new ExcelProcessManager();
            pm.Lock();

            foreach (Word.Bookmark mark in Globals.ThisAddIn.Application.ActiveDocument.Bookmarks) {
                // must cast
                // the inlineshape does not contain the chart property in pia.
                Interop.Word.InlineShapes inlineShapes = (Interop.Word.InlineShapes)mark.Range.InlineShapes;

                if (inlineShapes.Count > 0) {
                    try {
                        object Name = new object();
                        Name = mark.Name;

                        Object[,] obj = new Object[11, 3];
                        // fill data to obj
                        /*     ------------------------------------
                         *     |              |  收入  |  支出   |
                         *     ------------------------------------
                         *     |  2012/03/01  |  1023.2 |  304.23  |
                         *     -------------------------------------
                         *     |  2012/03/02  |  1123.2 |  314.23  |
                         *     -------------------------------------
                         *     |  2012/03/03  |  1223.2 |  674.23  |
                         *     -------------------------------------
                         *     |  2012/03/04  |  1043.2 |  124.23  |
                         *     -------------------------------------
                         *     |  2012/03/05  |  1083.2 |  384.23  |
                         *     -------------------------------------
                         *     |  2012/03/06  |  923.2  |  404.23  |
                         *     -------------------------------------
                         *     |  2012/03/07  |  2023.2 |  305.23  |
                         *     -------------------------------------
                         *     |  2012/03/08  |  1623.2 |  303     |
                         *     -------------------------------------
                         *     |  2012/03/09  |  1403.2 |  314.23  |
                         *     -------------------------------------
                         *     |  2012/03/10  |  1003.2 |  340     |
                         *     -------------------------------------
                         */
                        //添加横向第一列作为标题
                        obj[0, 0] = string.Empty;
                        obj[0, 1] = "收入";
                        obj[0, 2] = "支出";

                        DateTime dt = new DateTime(2012, 3, 1);
                        Random rnd = new Random();
                        int last = 1000;
                        // fill data
                        for (int i = 1; i < 11; i++) {
                            obj[i, 0] = dt.ToString("yyyy/MM/dd");
                            obj[i, 1] = last + rnd.Next(i, 100);
                            obj[i, 2] = last - rnd.Next(i, 100);
                            last = (int)obj[i, 1];
                            dt = dt.AddDays(1);
                        }

                        Interop.Word.Chart chart = inlineShapes[1].Chart;
                        ChartUpdate(chart, Name.ToString(), obj);
                    } catch (Exception ex) {
                        //logger.Warn("Chart update failed!", ex);
                    }
                }
            }

            pm.Release();
        }

        protected void ChartUpdate(Interop.Word.Chart chart, string bookMark, Object[,] dataArr) {
            if (chart == null) {
                //logger.Warn("Word.Chart is null!");
                return;
            }

            if (dataArr == null) {
                //logger.Warn("Data is null!");
                return;
            }

            Object oMissing = System.Reflection.Missing.Value;
            Interop.Word.Chart chrt;
            Microsoft.Office.Interop.Excel.Workbook wb = null;

            Object bk = bookMark;
            try {
                //xlApp.ScreenUpdating = false;
                chrt = chart;

                if (chrt.ChartData == null) {
                    //logger.Warn("chart.ChartData is null!");
                    return;
                }

                chrt.ChartData.Activate();
                wb = (Excel.Workbook)chrt.ChartData.Workbook;

                if (wb == null) {
                    //logger.Warn("chart.ChartData.Workbook is null!");
                    return;
                }
                wb.Application.ScreenUpdating = false;
                wb.Application.WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMinimized;

                Microsoft.Office.Interop.Excel.Worksheet wSh = (Excel.Worksheet)wb.Worksheets[1];

                if (wSh == null) {
                    //logger.Warn("chart.ChartData.Workbook.Worksheets[1] is null!");
                    return;
                }

                // save formats
                wSh.Cells.ClearContents();
                Microsoft.Office.Interop.Excel.Range Rng = wSh.get_Range("A1", "A1");
                Rng.get_Resize(dataArr.GetUpperBound(0) + 1, dataArr.GetUpperBound(1) + 1).Value2 = dataArr;
                chrt.SetSourceData("'Sheet1'!" + Rng.get_Resize(dataArr.GetUpperBound(0) + 1, dataArr.GetUpperBound(1) + 1).get_Address(Type.Missing, Type.Missing, Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing), Type.Missing);
                chrt.Refresh();
                wb.Application.ScreenUpdating = true;

                wb.Close(Type.Missing, Type.Missing, Type.Missing);
            } catch (System.Runtime.InteropServices.COMException ex) {
                //logger.Warn("Update chart failed!", ex);
                //xlApp.ScreenUpdating = true;
            } finally {
                if (wb != null) {
                    try {
                        Marshal.ReleaseComObject(wb);
                    } catch { }
                }
            }
        }

        private class ExcelProcessManager {
            private bool _exits;
            public ExcelProcessManager() { }

            public void Lock() {
                _exits = Process.GetProcessesByName("EXCEL").Length > 0;
            }

            public void Release() {
                if (_exits)
                    return;

                Process[] excelproc = Process.GetProcessesByName("EXCEL");
                if (excelproc.Length > 0)
                    excelproc[0].Kill();
            }
        }


其中UpdateCharts和ChartUpdate方法用于生成数据,更新图表。ExcelProcessManager类用于管理Excel进程。

下载:

Interop.Word:http://code.google.com/p/interopword/

Demo:chartdemochart demo word.docx


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值