#excel #vba
Вопрос:
У меня есть книга Excel только для чтения, содержащая приложение VBA. Приложение сохраняет любые данные, которые необходимо сохранить в базе данных, и рабочая книга всегда закрывается без сохранения (путем настройки этой рабочей книги.Сохранено = True в BeforeClose).
У меня есть следующая проблема:
- Пользователь дважды щелкает книгу в проводнике Windows, книга открывается.
- Пользователь дважды щелкает книгу во второй раз в проводнике Windows.
- Подсказки Excel: «MyWorkbook.xls уже открыто. Повторное открытие приведет к удалению любых внесенных вами изменений. Вы хотите снова открыть MyWorkbook.xls?»
- Если пользователь нажимает «Да», книга снова открывается без выполнения обработчика событий BeforeClose экземпляра, который уже был открыт.
Это проблема в моем приложении, потому что это означает, что какой-то важный код очистки в обработчике событий BeforeClose не выполняется.
Может ли кто-нибудь предложить решение VBA для этого. Что может быть:
- Подавление запроса на повторное открытие книги. Вместо этого молча используйте уже открытый экземпляр.
- Каким-то образом заставьте BeforeClose или какой-либо другой обработчик событий запускаться в исходном экземпляре до его закрытия, чтобы я мог запустить свой код очистки.
Обновить:
Это Excel 2003.
Я могу избавиться от нежелательного приглашения, установив «Эта рабочая книга.Сохранено = True» в обработчике событий Workbook_SheetChanged (приложение VBA отвечает за сохранение любых данных, которые необходимо сохранить в базе данных, поэтому меня не волнует сохранение изменений в Excel).
Однако это не решает мою проблему: если я сделаю это, то двойной щелчок по книге в проводнике автоматически откроет книгу, но все равно сделает это без вызова обработчика событий «BeforeClose».
Итак, перефразируя вопрос:
- Есть ли в любом случае использование VBA для обнаружения и перехвата книги, открываемой таким образом?
Обновление 2
Принимая ответ BKimmel — похоже, что нет способа VBA перехватить это событие из книги.
Решение, которое я буду реализовывать, будет заключаться в перемещении кода приложения в надстройку XLA, которая автоматически загружается (если еще не загружена) при загрузке книги. Надстройка может обрабатывать события Open и BeforeClose, а также хранить информацию, необходимую для очистки.
Комментарии:
1. @Джо, может быть, ты мог бы рассказать людям точную версию Excel? Это может повлиять на ответ, который люди могут вам дать. 🙂
Ответ №1:
Чувак…это кажется легким, но это непросто. Я играл с каждым событием и свойством приложения/книги, которые я мог придумать за свои 7 или около того лет работы с Excel VBA, и я вообще не мог придумать ничего элегантного… Я думаю, что короткий ответ заключается в том, что на самом деле нет короткого элегантного решения этой проблемы (если оно есть, я бы очень хотел его увидеть). Это плохая новость.
Хорошей новостью является то, что, я думаю, есть способы обойти проблему…1 немного более элегантен, но потребует от вас переосмысления некоторых ваших методов, а другой грязный, но, вероятно, немного проще.
Более элегантный способ предполагает переосмысление и рефакторинг ваших методов…Я думаю, что причина, по которой я никогда не сталкивался с этой проблемой в своей работе, заключается в том, что в конце каждого из моих методов рабочая книга остается в «хорошем» состоянии… или, другими словами, если нужно выполнить «очистку», то это делается в конце каждого метода. Если это приведет к значительному снижению производительности, вы можете рассмотреть возможность установки логического флага и ограничения того, выполняется ли он в конце каждого из ваших других методов. (т. Е. runCleanup = ReturnTrueIfCleanupIsNeeded() Если (runCleanup = true) Затем Метод очистки() Завершается, Если)
Более грязный способ включал бы превращение всей рабочей книги в своего рода «специальный мьютекс» путем
1) копирования всего (оригинала) Рабочая книга в событии WorkBookОпен в другую (временную) Книгу и с помощью метода «Сохранить» на временной странице поместите ее в отдельное место.
2) Сохранение (исходного) пути.
3) добавление кода для книги событие Open, который проверяет (темп) и, либо) сам закрывает сразу и активирует темп или B) перезаписывает себя (темп), а затем использует сохранить как
4) поймать событие до того, как пользователь сохраняет книгу и сохранить ее на как на оригинальные месте, и временное местоположение.
5) В событии WorkBookClose выполните любую необходимую очистку и сохраните временную запись в исходное местоположение.
Смысл всего этого в том, чтобы избежать «столкновения», которое происходит, когда вы дважды открываете книгу-по сути, создавая временную книгу при первом открытии и сохраняя ее в другом месте (может быть, вы даже могли бы скрыть файл?) вы гарантируете, что, когда пользователь нажимает на оригинал, он не столкнется с данными, с которыми он уже работает в приложении. (Конечно, у этого есть свои проблемы/вопросы, такие как «Что, если я не знаю, к каким путям у пользователя есть доступ для сохранения временного файла» или «Что, если пользователь откроет файл temp XLS…но именно поэтому я назвал егогрунтовым путем)»
Я знаю, что это много, особенно если вы не привыкли работать с VBA; Если вы хотите, чтобы я опубликовал какой-то код, который поможет вам выполнить любой из этих шагов, оставьте комментарий, и я это сделаю.
Спасибо за интересный вопрос.
Комментарии:
1. В любом случае, спасибо. Копирование во временную книгу-интересная идея, но я думаю, что будет проще перепроектировать приложение, чтобы удалить зависимость от очистки при закрытии. Мне кажется ошибкой, что событие BeforeClose не запускается в этой ситуации.
2. NB На самом деле я никогда не сохраняю книгу (она только для чтения), поэтому в моем случае нет необходимости в сохранении как во временной, так и в оригинальной версии.
3. Да, я бы сказал, что, по крайней мере , в документации MSDN должно быть указано, что вы не можете полагаться на то, что из-за этого произойдет увольнение. Мне все еще интересно посмотреть, не придумает ли кто-нибудь еще здесь что-нибудь творческое, о чем мы не думаем.
4. Еще раз спасибо. Как отмечалось в правке вопроса, я перенесу приложение в надстройку XLA (что, вероятно, в любом случае является лучшим решением).
Ответ №2:
Вы можете использовать некоторые специальные события приложения для обработки при повторном открытии книги и вручную запустить код Workbook_Close:
Создайте модуль класса под названием ApplicationController со следующим кодом:
Public WithEvents CApp As Application
Public CurrentWB as Workbook
Private Sub CApp_WorkbookOpen(ByVal wb As Excel.Workbook)
Dim sPathName As String
sPathName = wb.Name
if sPathName = CurrentWB.Name then CallSomeMethod()
End Sub
затем в вашем событии workbook_load сделайте что-то вроде:
Public controller as new ApplicationController
Private Sub Workbook_Open()
set controller.CApp = Excel.Application
set controller.CurrentWB = ThisWorkbook
End Sub
теперь, когда excel откроет новую книгу, вы зафиксируете событие и запустите свой метод безопасности. Вы даже можете предотвратить повторное открытие книги, если захотите.
Комментарии:
1. Нет, это не сработает. Я пытался обработать Application_WorkbookOpen, но он вызывается после того, как предыдущий экземпляр уже закрыт.
2. Есть ли шанс, что вы могли бы запустить этот код при открытии книги, а не при закрытии книги? Как процесс «начала дня» или что-то в этом роде? Или при закрытии книги установите флаг, чтобы, если этот флаг не существует, код выполнялся при открытии?
3. Нет, я не могу запустить его в Workbook_Open. И я не могу установить флаг при закрытии, потому что книга доступна только для чтения. В любом случае, спасибо.
Ответ №3:
Вы также можете отключить приглашение,:
Это приведет к повторному открытию открытого файла без предупреждений.. но обратите внимание, что любые изменения отбрасываются!
Application.DisplayAlerts = False
Workbooks.Open (sPath)
Application.DisplayAlerts = True
Это решение работало для моих нужд