Как правильно использовать событие WorkbookBeforeClose? - PullRequest
7 голосов
/ 29 марта 2010

Ежедневно человеку необходимо проверять, чтобы определенные рабочие книги были правильно обновлены с рыночными данными Bloomberg и Reuters; то есть все данные прошли и что «цифры выглядят правильно». В прошлом люди не проверяли «цифры», что приводило к неточной загрузке в другие системы.

Идея заключается в том, что необходимо разработать «что-то», чтобы предотвратить закрытие / сохранение книги при использовании, если он / она не проверил, что обновления являются правильными / точными. Действие numbers look correct является чисто интуитивным упражнением, поэтому не будет закодировано каким-либо образом.

Простым решением было предложить пользователям перед закрытием конкретной книги проверить, что данные проверены.

Используя VSTO SE для Excel 2007, была создана надстройка, которая подключается к событию WorkbookBeforeClose, которое инициализируется в надстройке ThisAddIn_Startup

private void wb_BeforeClose(Xl.Workbook wb, ref bool cancel)
{
    //.... snip ...

    if (list.Contains(wb.Name))
    {
        DailogResult result = MessageBox.Show("some message", "sometitle", MessageBoxButtons.YesNo);

        if (result != DialogResult.Yes)
        {
            cancel = true; // i think this prevents the whole application from closing
        } 
    } 
}

Я обнаружил следующее ThisApplication.WorkbookBeforeSave против ThisWorkbook.Application.WorkbookBeforeSave, в котором рекомендуется использовать событие ThisApplication.WorkbookBeforeClose, которое, как мне кажется, является тем, что я делаю, поскольку охватит все открытые файлы.

Проблема, с которой я столкнулся при таком подходе, состоит в том, что при условии, что у меня открыто несколько файлов, некоторые из которых находятся в моем list, событие не позволяет Excel закрывать все файлы последовательно. Теперь требуется, чтобы каждый файл закрывался индивидуально. Редактировать : это происходит, когда Выход из Excel используется из меню Файл.

Вопросы

  1. Правильно ли я использую событие WorkbookBeforeClose и является ли это эффективным и действенным использованием события?
  2. Следует ли использовать событие уровня приложения или событие уровня документа ?
  3. Является ли описанное выше поведение нормальным ?
  4. При использовании событий рабочей книги в надстройке приветствуются любые другие предложения.

Обновление [30 марта 2010 года]:

Повозившись, я также попробовал следующее, пытаясь связать обработчик событий BeforeClose с каждой книгой, которая была открыта, как предложено по ссылке выше.

private void ThisAddIn_Startup(...)
{
    // snip
    Globals.ThisAddin.Application.WorkbookOpen += Application_Open; 
}

private void Application_Open(XL.Workbook wb)
{
    wb.BeforeClose += Document_WorkbookBeforeClose; // method does the same as above
}

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

Этот метод кажется ошибочным по сравнению с моим первоначальным подходом. Одна вещь, в которой я не уверен или чувствую себя комфортно, это привязка события при каждом открытии документа.

Обновление [07-Apr-2010]:

Предложенный Гленом ответ полезен, но не затрагивает актуальные вопросы, поэтому я прояснил последний вопрос немного подробнее.

Я также нашел этот блог Как получить закрытое событие Excel VSTO Workbook , что в некоторой степени относится к моей проблеме, поскольку его можно использовать в альтернативном подходе к моему решению с использованием подхода типа монитора к обработка рабочих книг (и, возможно, также использование недавно представленного события OnWorkbookClosed).

Обновление [08-апр-2010]:

Кажется, есть некоторая путаница, меня не беспокоит какая-либо проверка на самих книгах, а вопрос о правильности метода, который я использую (то есть с использованием события WorkbookBeforeClose уровня приложения). Комментарий @Mathias ниже показывает правильное понимание части проблемы относительно вопроса 3, хотя я думаю, что это стандартное поведение excel. Решение этой проблемы состояло в том, чтобы создать функцию закрытия, которая закрывает только мои определенные файлы.

  1. Является ли описанное выше поведение нормальным ? Да, но почему? Поскольку надстройка подключается к событию уровня приложения, проверка и отмена события блокирует приложение от закрытия любых дальнейших рабочих книг. Ключом здесь является аргумент ref bool cancel (cancel=false разрешает нормальное закрытие книги (по умолчанию), cancel=true предотвращает закрытие книги)

VS 2005 с VSTO SE

Ответы [ 3 ]

7 голосов
/ 08 апреля 2010

Используется уровень приложения WorkbookBeforeClose. Проблема заключается в том, что при вызове WorkbookBeforeClose файлы не сохраняются из-за неправильного поведения. Если это не так, событие Save сработает, и вы фактически проиграли событие WorkbookBeforeClose, поскольку оно уже произошло. Вот некоторый код VBA, который помогает справиться с этим.

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If Not Me.Saved Then
        NotSavedPrompt = Me.Name & " has not been saved. Would you like to save now?"
        SaveYesNo = MsgBox(NotSavedPrompt, vbQuestion + vbYesNoCancel)
        Select Case SaveYesNo
            Case vbYes
                Me.Save
            Case vbNo
                Me.Saved = True
            Case vbCancel
                Cancel = True
                Exit Sub
          End Select
    End If
    Call MyRoutine() //'this should be your sub that does what you want
End Sub
3 голосов
/ 03 апреля 2010

Поскольку у вас есть проблемы с этим подходом, и Excel может не позволить вам делать то, что вам нужно, возможно, вы могли бы рассмотреть другой подход для решения общей проблемы.

Не могли бы вы встроить что-то в книгу, помечая ее как «Проверено / Не проверено», основываясь на том, проверял ли кто-нибудь номера? В зависимости от того, как на самом деле используется рабочая книга (не ясно из вопроса), способ показать ее как непроверенную может варьироваться ... (визуально) установить цвет фона на светлый оттенок красного или (программно) изменить используемое имя диапазон, чтобы указать на пустую область, чтобы другие надстройки / макросы не могли найти данные.

Пользователь, который должен проверить рабочую книгу, должен будет нажать кнопку (в рабочей книге или на панели инструментов), чтобы указать, что он подтвердил ее. Затем ваш код отменит вышеуказанные изменения и установит флаг, указывающий, что рабочая книга была проверена. Это может быть в скрытой ячейке где-то в книге или в свойствах модуля VBA.

Чтобы подвести итоги ... при открытии, отметьте флаг. Если не установлено, измените книгу, чтобы она выглядела непроверенной. Если он установлен, то никаких изменений не требуется. Когда пользователь проверяет рабочую книгу, установите флаг и сохраните его навсегда.

Надеюсь, это поможет!

1 голос
/ 08 апреля 2010
  1. Правильно ли я использую событие WorkbookBeforeClose и является ли это эффективным и действенным использованием события?

    Я не могу найти более подходящее событие для использования. Тем не менее, я думаю, что другой подход будет иметь функцию Save&Close, которая использует событие WorkbookBeforeSave

  2. Следует ли использовать событие уровня приложения или событие уровня документа ?

    На момент написания этого я бы сказал, да. Поскольку я не могу создать надстройку уровня документа с помощью имеющихся у меня инструментов, это лучшее из доступных решений. Если бы инструменты были доступно, я бы изменил свойства документа _AssemblyName и _AssemblyLocation соответствующих файлов. Однако я бы изменил стратегию решения, используя шаблоны и сохраняя файлы по мере необходимости. Кроме того, перед сохранением, не исследовав это полностью, добавьте / удалите правильные свойства документа. Событие на уровне документа вполне подошло бы с использованием подхода, описанного выше.

  3. Является ли описанное выше поведение нормальным?

    Да, но почему? Поскольку надстройка подключается к событию уровня приложения, проверка и отмена события блокирует приложение от закрытия любых дальнейших рабочих книг. Ключом здесь является аргумент ref bool cancel (cancel = false разрешает нормальное закрытие книги (по умолчанию), cancel = true предотвращает закрытие книги). Если я ошибаюсь, пожалуйста, дайте мне знать.

  4. При использовании событий рабочей книги в надстройке приветствуются любые другие предложения

    См. Ответы выше для альтернативных подходов и использования различных событий.

...