2010-05-04 20 views
5

Một hi tất cả,Tự động hóa Excel: Đóng sự kiện thiếu

Tôi đang thực hiện tự động hóa Excel qua Interop trong C# và tôi muốn được thông báo khi sổ làm việc bị đóng. Tuy nhiên, không có sự kiện Đóng trên sổ làm việc cũng như sự kiện Thoát khỏi ứng dụng.

Có ai đã làm điều đó trước đây không? Làm cách nào để viết một đoạn mã phản ứng với sổ làm việc đang được đóng (chỉ được thực thi nếu sổ làm việc là thực sự là đã đóng)? Tốt nhất nên xảy ra sau khi đóng sổ làm việc, vì vậy tôi có thể dựa vào tệp để phản ánh tất cả thay đổi.

tin chi tiết về những gì tôi tìm thấy cho đến nay:

Có một BeforeClose() sự kiện, nhưng nếu có sự thay đổi chưa được lưu sự kiện này được nâng lên trước khi người dùng được hỏi liệu để cứu họ, vì vậy tại thời điểm này tôi có thể xử lý sự kiện, tôi không có tệp cuối cùng và tôi không thể phát hành các đối tượng COM, cả hai thứ mà tôi cần phải có/làm. Tôi thậm chí không biết liệu sổ làm việc có thực sự bị đóng hay không, vì người dùng có thể chọn hủy đóng.

Sau đó, có sự kiện BeforeSave(). Vì vậy, nếu người dùng chọn "Có" để lưu các thay đổi chưa được lưu, thì BeforeSave() được thực thi sau BeforeClose(). Tuy nhiên, nếu người dùng chọn "Hủy bỏ", sau đó nhấn "tập tin-> lưu", cùng một thứ tự chính xác của các sự kiện được thực thi. Hơn nữa, nếu người dùng chọn "Không", thì BeforeSave() sẽ không được thực thi. Điều tương tự cũng được giữ miễn là người dùng không nhấp vào bất kỳ tùy chọn nào trong số các tùy chọn này.

Trả lời

4

tôi đã tạo ra một hack sử dụng một cách tiếp cận bỏ phiếu giống như, và nó hoạt động:

Với bảng tính để quan sát, tôi tạo ra một chủ đề mà theo định kỳ cố gắng để thấy rằng bảng tính trong bộ sưu tập sách bài tập.

(Lớp DisposableCom là giải pháp hiện tại của tôi để properly cleanup COM objects.)

Excel.Application app = wbWorkbook.Application; 
string sWorkbookName = wbWorkbook.Name; 

Thread overseeWorkbooksThread = new Thread(new ThreadStart(
    delegate() 
    { 
     bool bOpened = false; 

     Excel.Workbooks wbsWorkbooks = app.Workbooks; 
     using (new DisposableCom<Excel.Workbooks>(wbsWorkbooks)) 
     { 
      while (true) 
      { 
       Thread.Sleep(1000); 

       if (wbsWorkbooks.ContainsWorkbookProperly(sWorkbookName)) 
        bOpened = true; 
       else 
        if (bOpened) 
         // Workbook was open, so it has been closed. 
         break; 
        else 
        { 
         // Workbook simply not finished opening, do nothing 
        } 
      } 

      // Workbook closed 
      RunTheCodeToBeRunAfterWorkbookIsClosed(); 
     } 
    })); 

overseeWorkbooksThread.Start(); 

Các phương pháp khuyến nông "ContainsWorkbookProperly" trông như thế này:

public static bool ContainsWorkbookProperly(this Excel.Workbooks excelWbs, 
    string sWorkbookName) 
{ 
    Excel.Workbook wbTemp = null; 
    try 
     wbTemp = excelWbs.Item(sWorkbookName); 
    catch (Exception) 
    { 
     // ignore 
    } 

    if (wbTemp != null) 
    { 
     new DisposableCom<Excel.Workbook>(wbTemp).Dispose(); 
     return true; 
    } 

    return false; 
} 

Tôi vẫn sẽ quan tâm nếu có một đơn giản hơn hoặc giải pháp tốt hơn.

-1

Bạn có thể sử dụng cả hai sự kiện không? Trên BeforeClose() thiết lập một lá cờ, sau đó BeforeSave() xem nếu cờ được thiết lập. Bạn sẽ cần một cách để thiết lập lại nó, tuy nhiên, trong trường hợp BeforeClose() được kích hoạt và BeforeSave() thì không. Không chắc chắn nếu có cái gì khác có thể giúp với điều đó.

Chỉnh sửa: Có vẻ như bạn đã đề cập đến điều này với "đúng thứ tự các sự kiện được thực thi". Nhưng nếu bạn có thể tìm thấy một cách để thiết lập lại nó (một "Hủy bỏ" sự kiện?) Nó có thể làm việc.

+0

Xin chào Nelson - vâng, tôi đã bảo hiểm điều đó. Vấn đề là "và BeforeSave() không phải" một phần của đề xuất của bạn là semidecidable. Nếu nó không được gọi, tôi có thể chờ đợi nhưng không bao giờ quyết định liệu điều này có nghĩa là anh ta bị hủy bỏ, anh ta đã chọn không, hoặc anh ta vẫn chưa nhấp vào bất kỳ nút nào. – chiccodoro

3

Đây không phải là mã của tôi, nhưng điều này đã làm việc một điều trị cho tôi:

https://gist.github.com/jmangelo/301884

Sao chép dán:

using System; 
using Excel = Microsoft.Office.Interop.Excel; 

namespace Helpers.Vsto 
{ 
    public sealed class WorkbookClosedMonitor 
    { 
     internal class CloseRequestInfo 
     { 
      public CloseRequestInfo(string name, int count) 
      { 
       this.WorkbookName = name; 
       this.WorkbookCount = count; 
      } 

      public string WorkbookName { get; set; } 

      public int WorkbookCount { get; set; } 
     } 

     public WorkbookClosedMonitor(Excel.Application application) 
     { 
      if (application == null) 
      { 
       throw new ArgumentNullException("application"); 
      } 

      this.Application = application; 

      this.Application.WorkbookActivate += Application_WorkbookActivate; 
      this.Application.WorkbookBeforeClose += Application_WorkbookBeforeClose; 
      this.Application.WorkbookDeactivate += Application_WorkbookDeactivate; 
     } 

     public event EventHandler<WorkbookClosedEventArgs> WorkbookClosed; 

     public Excel.Application Application { get; private set; } 

     private CloseRequestInfo PendingRequest { get; set; } 

     private void Application_WorkbookDeactivate(Excel.Workbook wb) 
     { 
      if (this.Application.Workbooks.Count == 1) 
      { 
       // With only one workbook available deactivating means it will be closed 
       this.PendingRequest = null; 

       this.OnWorkbookClosed(new WorkbookClosedEventArgs(wb.Name)); 
      } 
     } 

     private void Application_WorkbookBeforeClose(Excel.Workbook wb, ref bool cancel) 
     { 
      if (!cancel) 
      { 
       this.PendingRequest = new CloseRequestInfo(
        wb.Name, 
        this.Application.Workbooks.Count); 
      } 
     } 

     private void Application_WorkbookActivate(Excel.Workbook wb) 
     { 
      // A workbook was closed if a request is pending and the workbook count decreased 
      bool wasWorkbookClosed = true 
       && this.PendingRequest != null 
       && this.Application.Workbooks.Count < this.PendingRequest.WorkbookCount; 

      if (wasWorkbookClosed) 
      { 
       var args = new WorkbookClosedEventArgs(this.PendingRequest.WorkbookName); 

       this.PendingRequest = null; 

       this.OnWorkbookClosed(args); 
      } 
      else 
      { 
       this.PendingRequest = null; 
      } 
     } 

     private void OnWorkbookClosed(WorkbookClosedEventArgs e) 
     { 
      var handler = this.WorkbookClosed; 

      if (handler != null) 
      { 
       handler(this, e); 
      } 
     } 
    } 

    public sealed class WorkbookClosedEventArgs : EventArgs 
    { 
     internal WorkbookClosedEventArgs(string name) 
     { 
      this.Name = name; 
     } 

     public string Name { get; private set; } 
    } 
} 

Khi tôi sử dụng nó tôi đã thay đổi nó từ trở lại tên của sổ làm việc để tham chiếu đến sổ làm việc.

Các vấn đề liên quan