关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
一般在VSTO打开一个窗体用show方法。如下图(一个简单的测试项目):
Ribbon上有个按钮,该按钮点击事件是打开一个FormTest窗体。
代码看上去没什么问题,测试运行看看效果。
细心的同学可以发现,任务栏上面有两个Excel窗口的标志。
若此时再点击一下Excel的单元格,这个FormTest窗体会被Excel挡住。
通常Excel内自己窗口的弹窗不会被Excel本身挡住,就像查找替换窗体。
留意任务栏的Excel窗口标志,只有一个!
那我们要如何才能实现和查找替换窗口一样的效果呢?在Excel内弹窗置顶。
这里先说说两种临时解决方案。
1)用ShowDialog方法打开窗体。不过该方法会导致无法在打开窗体的时候,操作Excel单元格。
2)设置窗体的TopMost属性为True。
但该属性是全局置顶,而不是Excel内部置顶。
可以从上图看出,遮住了记事本的窗口。而且任务栏的Excel窗口标志还是两个。
正确的解决方法如下。使用窗体Show方法的第2个方法。
I开头的名称都表示该类型是一个接口。我们需要给这个窗口指定一个所有者。
通俗点说,告诉它的父亲是谁。由它父亲控制和管理,让其在内部打开。
为了方便统一管理,新建一个类,该类继承IWin32Window接口。代码如下:
using System; using System.Windows.Forms; //命名空间自行修改 namespace ExcelAddin1 { /// <summary> /// IWin32Window接口类,为了实现弹出的窗体在Excel内 /// </summary> public class ClsWinWrap:IWin32Window { private IntPtr m_Handle; //构造函数,参数是父窗口的句柄 public ClsWinWrap(IntPtr handle) { this.m_Handle = handle; } //构造函数,参数是父窗口的句柄 public ClsWinWrap(int handle) { this.m_Handle = new IntPtr(handle); } public IntPtr Handle { get { return m_Handle; } } //打开窗体,Show参数使用该类自身 public void Show(Form frm) { frm.Show(this); } //模式打开窗体,Show参数使用该类自身 public DialogResult ShowDialog(Form frm) { return frm.ShowDialog(this); } } }
继承该IWin32Window接口,只需要有Handle属性即可。
Handle是父窗体的句柄。Excel的Application句柄很容易获取,使用方法如下:
//Globals.ThisAddIn.Application.Hwnd 获取Excel Application的句柄 ClsWinWrap clsWinWrap = new ClsWinWrap(Globals.ThisAddIn.Application.Hwnd); FormTest form = new FormTest(); clsWinWrap.Show(form); //打开窗口,指定它的父亲是Excel
效果如下:
打开窗体之后,点击单元格。Excel不会遮住该窗体,该窗体也不是全局置顶(记得TopMost设置为False)。也可以编辑单元格。
但任务栏还是又标志显示。
这个再设置几个属性即可。我通常把窗体设置为不可改变大小,去掉最大化最小化按钮,去掉图标和任务栏显示。
设置完成之后,再打开测试。其效果就和查找替换框一致。
相关专题: VSTO的那些坑