У меня есть приложение, написанное на 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 и повторно добавлять ссылки, но не могу понять, в чем проблема. Любые идеи?





В качестве быстрого и грязного исправления я использовал следующий код в качестве альтернативы
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) не требуется.
Вышеупомянутое уже некоторое время работает нормально на нескольких различных настройках.
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 вернется, он выйдет из режима редактирования, и все, что было записано в отредактированную ячейку, все равно будет там.
должно быть Imports Office = Microsoft.Office.Core Импорт Microsoft.Office.Interop.Excel не Imports Office = Microsoft.Office.Core Импорт Microsoft.Office.Interop