【问题标题】:Workaround to see if Excel is in cell-edit mode in .NET查看 Excel 在 .NET 中是否处于单元格编辑模式的解决方法
【发布时间】:2019-12-07 07:38:27
【问题描述】:

我有一个用 VB.NET 编写的应用程序,它通过互操作与 Excel 进行交互。 我最终遇到了 Cell-edit 模式的已知问题(请参阅 MSDNstackoverflow 了解一些背景信息)。

我一直在尝试将建议的代码转换为 VB.NET,但不断收到以下错误:

Reference required to assembly 'office, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' containing the type 'Microsoft.Office.Core.CommandBars'. Add one to your project. (BC30652) - E:\ ... .vb:3471

原始C#代码(来自前面提到的文章)如下

private bool IsEditMode()
{
   object m = Type.Missing;
   const int MENU_ITEM_TYPE = 1;
   const int NEW_MENU = 18;

   // Get the "New" menu item.
   CommandBarControl oNewMenu = Application.CommandBars["Worksheet Menu Bar"].FindControl(MENU_ITEM_TYPE, NEW_MENU, m, m, true );

  if ( oNewMenu != null )
  {
     // Check if "New" menu item is enabled or not.
     if ( !oNewMenu.Enabled )
     {
        return true;
     }
  }
  return false;
}

我转换后的VB.NET代码如下

Private Function isEditMode() As Boolean
    isEditMode = False
    Dim m As Object = Type.Missing
    Const  MENU_ITEM_TYPE As Integer = 1
    Const  NEW_MENU As Integer = 18

    Dim oNewMenu As Office.CommandBarControl
    ' oExcel is the Excel Application object 
    ' the error is related to the below line
    oNewMenu = oExcel.CommandBars("Worksheet Menu Bar").FindControl(MENU_ITEM_TYPE, NEW_MENU, m, m, True)
    If oNewMenu IsNot Nothing Then
        If Not oNewMenu.Enabled Then
            isEditMode = True
        End If
    End If
End Function

我添加了对 Microsoft Office 对象库的 (COM) 引用

Imports Office = Microsoft.Office.Core
Imports Microsoft.Office.Interop

我有点卡住了。我已经尝试过间接引用 CommandBar 对象,并重新添加引用,但无法弄清楚问题所在。有任何想法吗?

【问题讨论】:

  • 应该是 Imports Office = Microsoft.Office.Core Imports Microsoft.Office.Interop.Excel 而不是 Imports Office = Microsoft.Office.Core Imports Microsoft.Office.Interop

标签: c# vb.net excel interop excel-interop


【解决方案1】:

作为一个快速和肮脏的修复,我使用以下代码作为替代

Private Function isEditMode() As Boolean
    isEditMode = False
    Try
        oExcel.GoTo("###")
    Catch Ex As Exception
       ' Either returns "Reference is not valid." 
       ' or "Exception from HRESULT: 0x800A03EC"
       If ex.Message.StartsWith("Exception") then isEditMode  = True
    End Try     
End Function

当 Excel 处于单元格编辑模式时,.GoTo 功能(和相应的菜单项)不可用。 如果代码运行时用户在单元格中工作,则为 .GoTo 函数提供一个虚拟目标将不会做任何事情,也不会影响任何事情。

额外的一点是不需要对 Microsoft Office 对象 (Microsoft.Office.Core) 库的引用。

【讨论】:

  • 以上在几种不同的设置上运行良好一段时间了。
【解决方案2】:
Function ExcelIsBusy()
ExcelIsBusy = Not Application.Ready
Dim m
m = Empty
Const MENU_ITEM_TYPE = 1
Const NEW_MENU = 18

Dim oNewMenu
Set oNewMenu = Application.CommandBars("Worksheet Menu Bar").FindControl(MENU_ITEM_TYPE, NEW_MENU, m, m, True)
If Not (oNewMenu Is Nothing) Then
    If Not oNewMenu.Enabled Then
        ExcelIsBusy = True
        'throw new Exception("Excel is in Edit Mode")
    End If
End If

End Function

【讨论】:

    【解决方案3】:

    我们之前使用过Application.CommandBars["Worksheet Menu Bar"] 方法,但遇到了一个缺陷。在编辑模式下退出 Excel 时,编辑模式取消,但该函数仍返回 true,因为菜单项已作为关机的一部分被禁用。

    我们改用了以下解决方案:

    public static bool ApplicationIsInEditMode(Application application)
    {
        try
        {
            application.ReferenceStyle = application.ReferenceStyle;
        }
        catch (COMException e)
        {
            return true;
        }
        return false;
    }
    

    【讨论】:

      【解决方案4】:

      较旧的帖子,但不是旧问题。上面用于检测和退出的解决方案很好,但我找到了另一种让 Excel 退出编辑模式的解决方案,它不需要使用 API 来查找窗口或使用 Sendkeys 来单击单元格,我的解决方案使用事件。 Excel 甚至可以处于编辑模式并最小化,这个解决方案仍然有效。如果您正在阅读本文,您可能不需要确切的代码,但如果您需要,请告诉我。 首先使用类似于之前解决方案的 try catch 检测 Excel 编辑模式,如果 Excel 处于编辑模式,则设置全局标志 True。 然后告诉 Excel 关闭。即使在编辑模式下,此操作也可用。 在 Excel OnClosing 事件中检查是否设置了 Global 标志,如果设置了 On Closing 事件“e.Cancel”为 True,这将停止 Excel 关闭。 将您的全局标志设置回 False,当 Excel 返回时,它将退出编辑模式,并且写入已编辑单元格的任何内容仍将存在。

      【讨论】:

        【解决方案5】:

        以下代码将检测excel是否处于编辑模式并退出:

        private void exitEditMode()
        {
        
            if (!isExcelInteractive())
            {
                // get the current range
                Excel.Range r = Globals.ThisAddIn.Application.ActiveCell;
                // bring Excel to the foreground, with focus
                // and issue keys to exit the cell
                xlBringToFront();
                Globals.ThisAddIn.Application.ActiveWindow.Activate();
                SendKeys.Flush();
                SendKeys.SendWait("{ENTER}");
                // now make sure the original cell is
                // selected…
                r.Select();
            }
        }
        
        private bool isExcelInteractive()
        {
            try
            {
                // this line does nothing if Excel is not
                // in edit mode. However, trying to set
                // this property while Excel is in edit
                // cell mdoe will cause an exception
                Globals.ThisAddIn.Application.Interactive = Globals.ThisAddIn.Application.Interactive;
                return true; // no exception, ecel is 
                // interactive
            }
            catch
            {
                return false; // in edit mode
            }
        }
        
        private void xlBringToFront()
        {
            SetForegroundWindow(Globals.ThisAddIn.Application.Hwnd);
        }
        
        [DllImport("User32.dll")]
        public static extern Int32 SetForegroundWindow(int hWnd);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多