简体   繁体   English

VSTO Excel加载项中的独立WPF表单无法保持焦点

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM