如何编写能在Office 2010/2007设计时能正常绘制并能进行交互的ActiveX控件
需求&问题:
最近在写一个产品时需要一个能在Word以及Excel中正常显示并进行交互操作的ActiveX控件,并且该控件必须要能与VSTO写的TaskPanel(TaskPanel由WPF MVVM实现)代码进行交互。
思路:
由于之前的写Word和Excel的TaskPanel采用的是VSTO,因此我优先想到用CSharp的UserControl来简化ActiveX空间的开发工作量,而且这样实现的话可以大大简化ActiveX控件与VSTO业务控制代码交互的实现。
问题:
花了半天时间将ActiveX写好后按部就班的将空间放到IE浏览器、ActiveX Test Container、VB下进行了简单的测试--测试均通过了,一切看似是那么美好!不过等我将我的ActiveX空间放到Excel中测试时我发现,我的ActiveX控件在设计时(Offie DesignMode)居然不能正常绘制,将ActiveX项目Attach到Excel进行调试后发现,原来UserControl在设计时的Paint事件居然根本就没有被触发,无语!#¥!@#。
放狗搜索后,发现了对ControlDesigner的介绍,貌似找到了解决设计时不能正常显示的办法啦。
有了思路,就动手吧->加System.Design引用->继承ControlDesigner实现自己的设计器行为->重写ControlDesigner中的OnPaintAdornments方法以确保设计时的正常显示->编译部署打开Excel进行测试->还是不行!?这次打击大了,居然还是失败了。再次翻看MSDN对ControlDesigner的帮助后发现,原来该属性只能保证你在VS2008或者VS2010的编辑器中编辑控件时的正常绘制--至此,这条路断了,得另寻思路了。
这个问题一直困扰了我大半年,期间各大搜索引擎都查了个遍还是一无所获,期间还是尝试用VB6再次写了一个验证型的ActiveX空间,不过貌似VB6对运行时绘制的支持也不给力。
解决方法:
最近终于又有时间来想这个问题了,翻看类似产品的ActiveX控件时我发现其绘制的界面让我联想起了我用ATL编写的一个界面不怎么样的ActiveX控件。难道用C++写的ActiveX就能解决这个问题?通过快速的在VS2010中创建一个MFC ActiveX空间原型,根据在Excel设计模式中的测试结果显示--成功了!原来关键时刻还是用上C++这把牛刀--谁说C++已经过时了,我看不见得!
总结&思考:
开发过程中发现疑难问题并不可怕,只要你在不断成长、不断地去探寻答案,无论最终你的最初目的有没有达到,你就会收到意外的惊喜。
补充:
1.在Excel中插入ActiveX后必须有代码来保证切换到设计模式,否则你的ActiveX控件将无法被选中。
请参考如下代码片段,
if (!Globals.ThisAddIn.Application.CommandBars.GetPressedMso("DesignMode")) { Globals.ThisAddIn.Application.CommandBars.ExecuteMso("DesignMode"); }
参考:
Addison.Wesley.Visual.Studio.Tools.for.Office.Using.C.Sharp.with.Excel.Word.Outlook.and.InfoPath.Sep.2005.chm
VSTO for Mere Mortals.pdf
VSTO 编程指南
MSDN VSTO: http://msdn.microsoft.com/zh-cn/office/hh133430.aspx
VCKbase最新COM视频教程
COM本质论
ATL Internals