Надстройка Excel-DNA выгружается, когда выбрана кнопка отмены «Вы хотите сохранить приглашение»

#c# #html #excel #wpf #excel-dna

#c# #HTML #excel #wpf #excel-dna

Вопрос:

Когда я нажимаю File -> Exit (или Alt F4) или X, мне предлагается диалоговое окно «Вы хотите сохранить изменения», где я могу выбрать «Отмена». Таким образом, Excel может продолжить работу, но моя надстройка Excel-dna больше никогда не уведомляется и остается незагруженной.

Изображение 1

Изображение 2

Изображение 3

Заранее спасибо, ребята!

Комментарии:

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

2. Привет, Джим! спасибо за ваш ответ. Какую версию Excel-DNA вы используете?

3. 0.34.6. Если вы подумаете об этом, для Excel действительно было бы ошибкой выгружать все надстройки, когда пользователь держит Excel открытым. Как вы думаете, почему она выгружает вашу надстройку? В этом должно быть что-то еще.

4. Возможно ли, что где-то в коде подписано событие WorkbookBeforeClose? Насколько мне известно, это событие срабатывает даже при нажатии кнопки отмены.

5. элармандо, ты прав! проблема в том, что в WorkbookBeforeClose есть некоторые действия для очистки всего, что касается боковых панелей, и, как вы сказали, запускается, даже если я нажал «Отмена». Есть ли обходной путь, чтобы что-то сделать, когда рабочий лист закрывается? … Я пытаюсь найти способ узнать, действительно ли книга закрыта, или какой-то обходной путь, подобный этому, чтобы установить флаг, чтобы я мог запустить свой код.

Ответ №1:

Армандо! Большое спасибо за вашу помощь!

Я обнаружил, что существует интерфейс IDTExtensibility2, в котором размещаются уведомления о событиях, которые происходят с надстройками, например, при их загрузке, выгрузке, обновлении и так далее. Поэтому я использую этот интерфейс с классом ExcelComAddIn в пространстве имен ExcelDNA.Интеграция:

 public class ExcelComAddIn : IDTExtensibility2
{
    public ExcelComAddIn();

    protected string ProgId { get; }

    public virtual void OnAddInsUpdate(ref Array custom);
    public virtual void OnBeginShutdown(ref Array custom);
    public virtual void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom);
    public virtual void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom);
    public virtual void OnStartupComplete(ref Array custom);
}
  

Я заметил, что метод OnBeginShutdown() запускается ПОСЛЕ диалогового приглашения! и это то, что я искал, поэтому я избавился от события WorkbookBeforeClose, переопределил метод OnBeginShutdown() и поместил свой код, который был в событии WorkbookBeforeClose, в OnBeginShutdown() вот так:

 public override void OnBeginShutdown(ref Array custom)
{
    base.OnBeginShutdown(ref custom);

    //I PUT MY CUSTOM CODE HERE:
    CloseAllPanes();

    ExcelTaskExecutor.Destroy();
}
  

И теперь, если пользователь решит нажать «Отмена» в диалоговом окне сохранения, OnBeginShutdown() не запускается, и мои панели все еще там!

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

Комментарии:

1. Спасибо, это действительно полезно

Ответ №2:

Насколько я понимаю, проблема возникает, когда WorkbookBeforeClose выполняется до того, как пользователь нажмет «Отмена». Есть несколько альтернатив.

Самый простой из них заключается в том, что вы можете сохранить активный wourkbook в событии WorkbookBeforeClose (объект wourkbook имеет методы save и saveas сохранить). Поскольку книга уже сохранена, диалоговое окно сохранения не будет отображаться, и пользователь не нажмет кнопку отмены.

Другим решением является вызов пользовательского диалогового окна сохранения в WorkbookBeforeClose. Я использовал следующий код в других проектах. WorkbookBeforeClose может выглядеть следующим образом:

   private void ActiveWorkbook_BeforeClose(ref bool Cancel)
    {
        DefaultSaveExcel(Excel.ActiveWorkbook,ref Cancel);

        if (!Cancel)
        {
            //if enters here is because the workbook is actually closing
            Delete(Excel.ActiveWorkbook.Name);
        }                     
    }
  

Фактическая реализация DefaultSaveExcel может выглядеть следующим образом:

  public  void DefaultSaveExcel(Workbook wb, ref bool Cancel)
    {
        while (wb.Saved == false amp;amp; Cancel == false)
        {
            var result = ShowMessageDialogSave();

            if (result == System.Windows.Forms.DialogResult.Yes)
            {
                var sa = CreateExcelSaveDialog(wb.FullName);

                if (sa.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    wb.SaveAs(sa.FileName);
                    wb.Save();

                }
            }
            else if (result == System.Windows.Forms.DialogResult.No)
            {
                wb.Saved = true;
            }
            else if (result == System.Windows.Forms.DialogResult.Cancel)
            {
                Cancel = true;
            }
        }
    }

    public  System.Windows.Forms.SaveFileDialog CreateExcelSaveDialog(string name = null)
    {
        var sa = new System.Windows.Forms.SaveFileDialog();
        sa.Filter = "Excel files (*.xlsx)|*.xlsx";
        if (!string.IsNullOrEmpty(name))
            sa.FileName = name;
        sa.CreatePrompt = true;

        return sa;
    }

    public  DialogResult ShowMessageDialogSave()
    {
        var app = (Microsoft.Office.Interop.Excel.Application)ExcelDna.Integration.ExcelDnaUtil.Application;
        NativeWindow xlMain = new NativeWindow();
        xlMain.AssignHandle(new IntPtr(app.Hwnd));

        var message = "Do you want to save pending changes?";

        if (Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.ToLower() == "es")
            message = "¿Desea guardar los cambios pendientes?";


        return System.Windows.Forms.MessageBox.Show(xlMain, message, "Microsoft Excel", System.Windows.Forms.MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning,MessageBoxDefaultButton.Button1);
    }
  

Надеюсь, это поможет,
Армандо