Обходной путь, чтобы узнать, находится ли Excel в режиме редактирования ячеек в .NET

У меня есть приложение, написанное на VB.NET, которое взаимодействует с Excel через взаимодействие. В конце концов я столкнулся с известной проблемой режима редактирования ячейки (см. MSDN и переполнение стека для некоторой предыстории).

Я пытался преобразовать предложенный код в 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

Я добавил ссылку (COM) на библиотеку объектов Microsoft Office.

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

Я как бы застрял. Я уже пробовал косвенно ссылаться на объект CommandBar и повторно добавлять ссылки, но не могу понять, в чем проблема. Любые идеи?

должно быть Imports Office = Microsoft.Office.Core Импорт Microsoft.Office.Interop.Excel не Imports Office = Microsoft.Office.Core Импорт Microsoft.Office.Interop

Anonymous Type 25.02.2010 07:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
5 379
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

В качестве быстрого и грязного исправления я использовал следующий код в качестве альтернативы

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

Функция .GoTo (и соответствующий пункт меню) недоступна, когда Excel находится в режиме редактирования ячеек. Предоставление функции .GoTo фиктивного назначения ничего не сделает и ни на что не повлияет, если пользователь работает в ячейке во время выполнения кода.

Дополнительным преимуществом является то, что ссылка на библиотеку Microsoft Office Object (Microsoft.Office.Core) не требуется.

Вышеупомянутое уже некоторое время работает нормально на нескольких различных настройках.

barry 31.01.2009 02:53
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

Ранее мы использовали метод Application.CommandBars["Worksheet Menu Bar"], но столкнулись с недостатком. При выходе из Excel в режиме редактирования режим редактирования отменяется, но функция по-прежнему возвращает истину, поскольку элементы меню были отключены как часть завершения работы.

Вместо этого мы использовали следующее решение:

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

Следующий код определит, находится ли 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);

Старый пост, но не старая проблема. Приведенное выше решение для обнаружения и выхода в порядке, но я нашел другое решение для вывода Excel из режима редактирования, которому не нужно использовать API для поиска окна или использовать Sendkeys для щелчка по ячейке, мое решение использует события. Excel может быть даже в режиме редактирования и свернут, и это решение по-прежнему будет работать. Если вы читаете это, вероятно, вам не понадобится точный код, но если вы это сделаете, дайте мне знать. Сначала определите режим редактирования Excel с помощью попытки, аналогичной предыдущим решениям, и установите глобальный флаг True, если Excel находится в режиме редактирования. Затем скажите Excel закрыть. Это действие будет доступно даже в режиме редактирования. В событии Excel OnClosing проверьте, установлен ли ваш глобальный флаг, и если да, установите для события On Closing 'e.Cancel' значение True, которое остановит закрытие Excel. Установите для глобального флага значение False, и когда Excel вернется, он выйдет из режима редактирования, и все, что было записано в отредактированную ячейку, все равно будет там.

Другие вопросы по теме