Excel as inlay frame in WPF has disabled ExcelWorksheet
Asked Answered
H

1

13

I found a solution to setup Excel instance in WPF by using the SetParent() function of Windows.

Problem is, that mouse and keyboard is not reacting to the sheet but to the Workbook it does.

Full sample Project Download here

I also tried with WindowsFormsHost but it has the same effect.

XAML

<Window x:Class="ExcelEditor.SimpleWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ExcelEditor"
    mc:Ignorable="d" Loaded="Window_Loaded" Closing="Window_Closing"
    Title="SimpleWindow" Height="450" Width="800">
<Grid x:Name="LayoutRoot">

</Grid>

C# code

    using System;
    using System.Windows;


namespace ExcelEditor
{
    /// <summary>
    /// Interaktionslogik für SimpleWindow.xaml
    /// </summary>
    public partial class SimpleWindow : Window
    {
        private Microsoft.Office.Interop.Excel.Application ExcelApplication;

        public SimpleWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(this); // <- testing only (no success)
            ExcelApplication = new Microsoft.Office.Interop.Excel.Application();
            ExcelApplication.DisplayAlerts = false;
            System.Windows.Interop.HwndSource hwnd = (System.Windows.Interop.HwndSource)System.Windows.Interop.HwndSource.FromVisual(this.LayoutRoot);
            var excelWnd = Microsoft.Win32.Interop.FindWindow("XLMAIN", null);
            GenerateTestData(ExcelApplication);
            var successOfParentSetup = Microsoft.Win32.Interop.SetParent(excelWnd, hwnd.Handle);
            var isMovedToLeftTop = Microsoft.Win32.Interop.MoveWindow(excelWnd, 10, 10, 800, 600, true);
            ExcelApplication.Visible = true;
        }

        private void GenerateTestData(Microsoft.Office.Interop.Excel.Application excelApplication)
        {
            var excelWorkbook = excelApplication.Workbooks.Add();
            var excelWorksheet = excelWorkbook.Worksheets[1] as Microsoft.Office.Interop.Excel.Worksheet;
            excelWorksheet.Cells[1, 1] = "Today";
            excelWorksheet.Cells[2, 1] = DateTime.Now.ToString();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (ExcelApplication != null)
            {
                ExcelApplication.ActiveWorkbook.Close();
                ExcelApplication.Visible = false;
                ExcelApplication.Quit();
                ExcelApplication = null;
            }
        }
    }
}

Api calls

    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern bool SetWindowPos(
        IntPtr hWnd,               // handle to window
        IntPtr hWndInsertAfter,    // placement-order handle
        int X,                  // horizontal position
        int Y,                  // vertical position
        int cx,                 // width
        int cy,                 // height
        uint uFlags             // window-positioning options
    );

    [DllImport("user32.dll", EntryPoint = "MoveWindow")]
    public static extern bool MoveWindow(
        IntPtr hWnd,
        int X,
        int Y,
        int nWidth,
        int nHeight,
        bool bRepaint
    );
    [DllImport("USER32.DLL", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    //Sets a window to be a child window of another window
    [DllImport("USER32.DLL", SetLastError = true)]
    public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

Question is, how to enable the mouse and keyboard handling in Excel to allow editing the worksheet?

Excel not working propert as parent

*Tested at: Windows 10 x64, Single screen (optional dual screen) Excel 2016 MSO 32-Bit (16.0.10325.20082) out of Office 365

This issue is also reported on Microsoft Forum to check if there is a solution.

In the following video you see how the click sometimes will select cells and sometimes it will not recognize the mouse.

Excel

Horny answered 23/8, 2018 at 13:7 Comment(6)
Just downloaded and run your project and guess what: I'm able to edit the sheet, such as entering text and applying color. Didn't change any code. I'm running Windows 10 and Excel 2016, both 64-bit. Works when running from Visual Studio Professional 2017 (15.8.1) in debug mode as well as when running the executable directly from the bin/debug folder.Wynn
Does the problem also occur when you remove SetParent()?Wynn
Without SetParent the cells are editable and all is working correct in Excel. Thanks for adding your configuration.Horny
After reviewing your conversation with @Simon I suspect its the Message Pump filters causing your PCs to produce different results. There are 3 links, see the comments in this thread and in that thread see the comments and follow the links.Simeon
Good input. I added a WndProc listener and received for example focus message on load. When clicking in Excel window in the sheet, only Excel receives WinProc messages. WPF did not reveive any when working in Excel. As I expect because Excel should handle the cells itself without my WPF window.Horny
I might be late to the party. But I am not able to replicate the issue using your code. I am using Windows 10 x64, VS 2017 15.4.1, MS Office 2016 x32. Any hint?Apotheosis
A
1

You need to make sure Excel has been shown once before you can call SetParent. Of course, it looks ugly, so you also need to hide Excel UI somehow from the end-user. For example:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ...
        // get excel window
        var excelWnd = Microsoft.Win32.Interop.FindWindow("XLMAIN", null);

        // move excel somewhere outside the screen (of course you should compute it, not hardcode it)
        Microsoft.Win32.Interop.MoveWindow(excelWnd, -10000, -10000, 800, 600, true);

        // show it so it's initialized properly
        ExcelApplication.Visible = true;
        GenerateTestData(ExcelApplication);

        // now call SetParent
        Microsoft.Win32.Interop.SetParent(excelWnd, hwnd.Handle);

        // move it to parent
        Microsoft.Win32.Interop.MoveWindow(excelWnd, 10, 10, 800, 600, true);
    }
Anorexia answered 26/8, 2018 at 8:48 Comment(17)
But that doesn't explain why it worked at my computer without having to alter any code.Wynn
@bouke - No, but that wasn't the question. Using SetParent is a hack anyway, applications do not expect their parent to be changed like that.Anorexia
@SimonMourier Good idea. In my case it did not solve the issue. Could you compare with your solution that it did not work before and after the workaround it worked?Horny
@Horny - yes, I did all that. Maybe a timing issue.Anorexia
I also tried testwise with System.Windows.Forms.Application.DoEvents() before SetParent() without success. Also on another computer with Office 2013 the sheet is locked. Perhaps you can describe your computer settings?Horny
I have two very different machines but they have in common: Latest Windows 10 x64, Latest Office 365's Excel 16.0.916.2275 x64. I can build ExcelEditor.exe in x64 or x86 and it works for both. I can't test Excel x86.Anorexia
Can you check out, if it works immediate after application run but when focussing something else instead of Excel (like the DotNet application window) it will disable cell editing.Horny
@Horny - I've checked that out, and everything works fine with my code, no matter what I do :-)Anorexia
@Horny - I've also tested on Windows 7 64-bit with Excel Office 365 32-bit (french) and it works fine. Do you have a zip with all binaries files that I could test? There might be a problem with your config? FYI: you'll never get any help from Microsoft on this type of subject, this is totally off the grid.Anorexia
Thanks for this effort! It should be in shared download folder of this project description. my email and binaries included.Horny
@Horny - damn. It still works for me. Have you tried another machine? Like a virtual machine or something. Or is there anything in your config that could do weird things?Anorexia
I have tried about 12 machines, including virtual. All with same problem.Horny
@Horny - strange. Or maybe we're not doing the same thing. Can you record what you do with Steps Recorder : support.microsoft.com/en-us/help/22878/windows-10-record-steps and put it somewhereAnorexia
In case of your answers, I setup a clean Virtual device and it worked. After hours I found out, that most computers had Teamviewer installed once in their livetime. I very thank you and hope this will help others.Horny
Undo my answer. After restarting and testing, the AddOn was not the solution. It worked for 10 minutes in case of unknown issue and is still working on one other machine. But now it is no more. Now the state is as before. I deleted my answer.Horny
I recorded the issue with steps recorder. I can not share it public in case it contains private data but I updated the question with the new video.Horny
I have Team Foundation plugin installed as well (but you talk about teamviewer initially - typo ?) I do think there is something in your machines setup that hooks the keyboard or mouse globally or something like that.Anorexia

© 2022 - 2024 — McMap. All rights reserved.