引自免费微信小程序:皆我百晓生
在您的C# VSTO PowerPoint外接程序中,要将一个WPF窗体(ToolBar
)嵌入到PowerPoint窗口中并使其与PowerPoint窗口同步移动,您已正确地设置了WPF窗体的Owner
属性。然而,为了确保WPF窗体始终保持在PowerPoint窗口的特定位置(例如中下方),并在PowerPoint窗口移动时自动跟随,您还需要进行一些额外的设置和处理。
以下是在现有代码基础上添加所需功能的详细步骤及代码示例:
-
调整WPF窗体的位置:
在SetPowerPointWindowOwner()
方法之后,添加一个方法来计算并设置ToolBar
在PowerPoint窗口中的初始位置。确保它位于PowerPoint窗口的中下方。
private void SetToolBarInitialPosition()
{
RECT pptWindowRect;
GetWindowRect(new HandleRef(null, app.HWND), out pptWindowRect);
double pptWidth = pptWindowRect.Right - pptWindowRect.Left;
double pptHeight = pptWindowRect.Bottom - pptWindowRect.Top;
// 以下计算将使ToolBar位于PowerPoint窗口的中下方
double toolBarLeft = pptWindowRect.Left + (pptWidth / 2) - (toolBar.Width / 2);
double toolBarTop = pptWindowRect.Bottom - toolBar.Height;
toolBar.Left = toolBarLeft;
toolBar.Top = toolBarTop;
}
上述代码使用了GetWindowRect
函数(需要引入User32.dll
库)来获取PowerPoint窗口的大小和位置。然后根据这些信息计算出ToolBar
应放置的坐标。
-
监听PowerPoint窗口移动事件:
要让ToolBar
随PowerPoint窗口移动而实时更新其位置,需要监听PowerPoint窗口的大小更改和移动事件。由于VSTO API并未直接提供此类事件,您可以利用Windows消息处理机制来监听WM_SIZE
和WM_MOVE
消息。为此,向您的外接程序类添加一个WndProc
方法,并注册一个隐藏的辅助窗口来接收这些消息。
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
const int GWL_WNDPROC = -4;
IntPtr prevWndProcPtr = IntPtr.Zero;
protected override void OnStartup()
{
base.OnStartup();
prevWndProcPtr = SetWindowLong(new HandleRef(null, app.HWND), GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(WndProc));
}
private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
if (msg == 0x0005 /* WM_SIZE */ || msg == 0x0003 /* WM_MOVE */)
{
UpdateToolBarPosition();
}
return CallWindowProc(prevWndProcPtr, hWnd, msg, wParam, lParam);
}
这段代码通过SetWindowLong
函数为PowerPoint窗口设置一个新的窗口过程回调(即WndProc
方法),以便捕获WM_SIZE
和WM_MOVE
消息。当接收到这些消息时,调用UpdateToolBarPosition
方法来重新计算并更新ToolBar
的位置。
-
实现UpdateToolBarPosition
方法:
创建一个方法来根据当前PowerPoint窗口的位置和大小重新计算并设置ToolBar
的位置。
private void UpdateToolBarPosition()
{
RECT pptWindowRect;
GetWindowRect(new HandleRef(null, app.HWND), out pptWindowRect);
double pptWidth = pptWindowRect.Right - pptWindowRect.Left;
double pptHeight = pptWindowRect.Bottom - pptWindowRect.Top;
double toolBarLeft = pptWindowRect.Left + (pptWidth / 2) - (toolBar.Width / 2);
double toolBarTop = pptWindowRect.Bottom - toolBar.Height;
MoveWindow(toolBar.Handle, (int)toolBarLeft, (int)toolBarTop, (int)toolBar.Width, (int)toolBar.Height, true);
}
此方法与SetToolBarInitialPosition
类似,但它是动态响应PowerPoint窗口变化时调用的。使用MoveWindow
函数直接设置ToolBar
的屏幕坐标。
现在,将上述代码片段整合到您的外接程序中,ToolBar
应该会始终固定在PowerPoint窗口的中下方,并随PowerPoint窗口的移动而自动跟随。记得在ShowToolBar
方法中调用SetToolBarInitialPosition
方法:
private void ShowToolBar()
{
try
{
toolBar = new ToolBar(app);
SetPowerPointWindowOwner();
SetToolBarInitialPosition();
toolBar.Show();
// ...其他事件注册代码...
}
// ...异常处理代码...
}
这样,您就实现了所需的WPF窗体嵌入PowerPoint并跟随其移动的功能。