[英]Standalone WPF Form in VSTO Excel Addin Won't Keep Focus
I am creating a VSTO Plugin for Excel and my first attempt works, but I am not happy with the design. 我正在创建用于Excel的VSTO插件,并且第一次尝试可以工作,但是我对设计不满意。 As standard VSTO only handles Windows Forms.
作为标准,VSTO仅处理Windows窗体。 I am getting in to WPF now and have found the options for layout and animations make for a much better user experience.
我现在进入WPF,发现布局和动画选项使用户体验更好。
I have now found that I can add a WPF Project to the VSTO Solution and call the forms that way... Excellent! 现在,我发现可以将WPF项目添加到VSTO解决方案中,并以这种方式调用表单...太好了!
The problem is when I load a form I do this: 问题是当我加载表单时,我这样做:
Dim NewForm as New NewForm
NewForm.Show()
This works fine, and the form opens, however if I try to type in a textbox, the form drops behind excel and the text goes in to the active cell in Excel. 这可以正常工作,并且可以打开表单,但是,如果我尝试在文本框中键入内容,则表单会落在excel之后,并且文本会进入Excel中的活动单元格。
If I do: 如果我做:
Dim NewForm as New NewForm
NewForm.ShowDialog()
it works fine. 它工作正常。 Unfortunately I cannot have the form being modal for my application.
不幸的是,我不能让表格成为我的申请的模态。 How can I get around this?
我该如何解决?
I use the following class: https://dl.dropboxusercontent.com/u/62538279/Help/OfficeDialog.cs 我使用以下类: https : //dl.dropboxusercontent.com/u/62538279/Help/OfficeDialog.cs
You'll notice that the ShowDialog() method is replaced 您会注意到ShowDialog()方法已被替换
The class also makes the dialog look like a Word VBA form (something my clients often want) 该类还使对话框看起来像Word VBA表单(我的客户经常想要的东西)
My dialog.xaml.cs class looks like (and the xaml matches): 我的dialog.xaml.cs类看起来像(和xaml匹配):
public partial class myDialog : OfficeDialog
-- Edit -- -编辑-
Here's the source code. 这是源代码。 I've been having trouble with it.
我一直有麻烦。 It occasionally slips behind the application (very rarely)
它偶尔会拖到应用程序后面(很少)
http://stackoverflow.com/questions/40374059/why-does-my-modal-wpf-dialog-slip-behind-ms-word/40401198#40401198 http://stackoverflow.com/questions/40374059/why-does-my-modal-wpf-dialog-slip-behind-ms-word/40401198#40401198
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
public class OfficeDialog : Window
{
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x0001;
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_NOZORDER = 0x0004;
const int SWP_FRAMECHANGED = 0x0020;
const uint WM_SETICON = 0x0080;
const int ICON_SMALL = 0;
const int ICON_BIG = 1;
/// <summary>
/// Sometimes get System.ComponentModel.Win32Exception: Invalid window handle
/// I'm pretty sure that this is because Word is shit at handling windows and has an internal memory leak
/// http://stackoverflow.com/questions/222649/winforms-issue-error-creating-window-handle
/// I'm not sure why this error isn't trapped and logged by the try catch below. Somehow it bubbles up to the calling routine..
/// </summary>
public OfficeDialog()
{
this.ShowInTaskbar = false;
//this.Topmost = true;
//Uri uri = new Uri("PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\\themes/aero.normalcolor.xaml", UriKind.Relative);
//Uri uri = new Uri("PresentationFramework.Classic;V3.0.0.0;31bf3856ad364e35;component\\themes/classic.xaml", UriKind.Relative);
//Resources.MergedDictionaries.Add(Application.LoadComponent(uri) as ResourceDictionary);
//var helper = new WindowInteropHelper(this);
//using (Process currentProcess = Process.GetCurrentProcess())
// helper.Owner = currentProcess.MainWindowHandle;
}
public new void ShowDialog()
{
try
{
var helper = new WindowInteropHelper(this);
using (Process currentProcess = Process.GetCurrentProcess())
helper.Owner = currentProcess.MainWindowHandle;
base.ShowDialog();
}
catch (System.ComponentModel.Win32Exception ex)
{
Message.LogWarning(ex);
//this.Topmost = true;
var helper = new WindowInteropHelper(this);
using (Process currentProcess = Process.GetCurrentProcess())
helper.Owner = currentProcess.MainWindowHandle;
base.ShowDialog();
}
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
RemoveIcon(this);
HideMinimizeAndMaximizeButtons(this);
//using (Process currentProcess = Process.GetCurrentProcess())
// SetCentering(this, currentProcess.MainWindowHandle);
}
public static void HideMinimizeAndMaximizeButtons(Window window)
{
const int GWL_STYLE = -16;
IntPtr hwnd = new WindowInteropHelper(window).Handle;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (int)(value & -131073 & -65537));
}
public static void RemoveIcon(Window w)
{
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper(w).Handle;
// Change the extended window style to not show a window icon
int extendedStyle = OfficeDialog.GetWindowLong(hwnd, GWL_EXSTYLE);
OfficeDialog.SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
// reset the icon, both calls important
OfficeDialog.SendMessage(hwnd, WM_SETICON, (IntPtr)ICON_SMALL, IntPtr.Zero);
OfficeDialog.SendMessage(hwnd, WM_SETICON, (IntPtr)ICON_BIG, IntPtr.Zero);
// Update the window's non-client area to reflect the changes
OfficeDialog.SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
static void SetCentering(Window win, IntPtr ownerHandle)
{
bool isWindow = IsWindow(ownerHandle);
if (!isWindow) //Don't try and centre the window if the ownerHandle is invalid. To resolve issue with invalid window handle error
{
//Message.LogInfo(string.Format("ownerHandle IsWindow: {0}", isWindow));
return;
}
//Show in center of owner if win form.
if (ownerHandle.ToInt32() != 0)
{
var helper = new WindowInteropHelper(win);
helper.Owner = ownerHandle;
win.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
else
win.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindow(IntPtr hWnd);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.