2010-05-04 17 views
5

एक और हाय सब घटना,एक्सेल स्वचालन बंद लापता

मैं सी # में Interop के माध्यम से एक्सेल स्वचालन कर रहा हूँ, और मैं जब किसी कार्यपुस्तिका बंद कर दिया है सूचित करना चाहते हैं। हालांकि, कार्यपुस्तिका पर कोई बंद घटना नहीं है और न ही एप्लिकेशन पर एक छोड़ घटना है।

कोई भी व्यक्ति उस से पहले किया गया है? मैं कोड का एक टुकड़ा जो कार्यपुस्तिका बंद किया जा रहा के प्रति प्रतिक्रिया करता है (यदि कार्यपुस्तिका वास्तव में बंद कर दिया है जो केवल निष्पादित किया जाता है) कैसे लिख सकता है? आदर्श रूप में है कि के बाद होना चाहिए कार्यपुस्तिका को बंद करने, इसलिए मैं सभी परिवर्तनों को प्रतिबिंबित करने के लिए फ़ाइल पर भरोसा कर सकते हैं।

मैं अब तक क्या मिला के बारे में विवरण:

एक BeforeClose() घटना नहीं है, लेकिन अगर कोई बिना सहेजे गए परिवर्तन हैं इस घटना से पहले उपयोगकर्ता कहा जा रहा है, उन्हें बचाने के लिए है कि क्या उठाया है पल मैं कर सकते हैं पर ऐसा घटना को संसाधित करें, मेरे पास अंतिम फ़ाइल नहीं है और मैं COM ऑब्जेक्ट्स को रिलीज़ नहीं कर सकता, दोनों चीजें जिन्हें मुझे करने की ज़रूरत है। मुझे यह भी पता नहीं है कि कार्यपुस्तिका वास्तव में बंद हो जाएगी, क्योंकि उपयोगकर्ता बंद करने का विकल्प चुन सकता है।

तो फिर वहाँ एक BeforeSave() घटना है। तो, उपयोगकर्ता चुनता है "हाँ" बिना सहेजे गए परिवर्तन को बचाने के लिए है, तो BeforeSave() BeforeClose के बाद निष्पादित किया जाता है()। हालांकि, यदि उपयोगकर्ता "निरस्त" चुनता है, तो "फ़ाइल-> सेव" हिट करता है, ईवेंट के सटीक उसी क्रम को निष्पादित किया जाता है। इसके अलावा, यदि उपयोगकर्ता "नहीं" चुनता है, तो पहले सेव() को निष्पादित नहीं किया जाता है। वही तब तक रहता है जब तक उपयोगकर्ता इन विकल्पों में से किसी एक पर क्लिक नहीं करता है।

उत्तर

4

मैं एक मतदान की तरह दृष्टिकोण का उपयोग कर एक हैक बना लिया है, और यह काम करता है:

कार्यपुस्तिका निरीक्षण करने के लिए देखते हुए, मैं एक धागा जो समय समय पर कार्यपुस्तिका संग्रह में है कि कार्यपुस्तिका खोजने की कोशिश करता पैदा करते हैं।

(DisposableCom वर्ग 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(); 

"ContainsWorkbookProperly" विस्तार के तरीकों इस तरह दिखता है:

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; 
} 

फिर भी मैं दिलचस्पी होगी अगर वहाँ एक सरल या बेहतर समाधान।

-1

तुम दोनों घटनाओं का उपयोग कर सकते हैं? पहले क्लोज़() पर एक ध्वज सेट करें, फिर पहले सेव() देखें कि ध्वज सेट है या नहीं। यदि आपको पहले क्लोज़() ट्रिगर किया गया है और पहले सेव() नहीं है, तो आपको इसे रीसेट करने का एक तरीका चाहिए। सुनिश्चित नहीं है कि कुछ और है जो उसमें मदद कर सकता है।

संपादित करें: ऐसा लगता है कि आपने इसे पहले से कवर किया है "ईवेंट के सटीक उसी क्रम को निष्पादित किया गया है"। लेकिन अगर आप इसे रीसेट करने का कोई तरीका ढूंढ सकते हैं (एक और "रद्द करें" ईवेंट?) यह काम कर सकता है।

+0

हाय नेल्सन - हाँ, मैंने पहले से ही इसे कवर किया है। समस्या यह है कि "और पहले सेव() नहीं है" आपके प्रस्ताव का हिस्सा semidecidable है। अगर इसे नहीं कहा जाता है, तो मैं इंतजार कर सकता हूं लेकिन यह तय नहीं करता कि इसका मतलब है कि वह निरस्त हो गया है, उसने कोई नहीं चुना है, या उसने अभी तक किसी भी बटन पर क्लिक नहीं किया है। – chiccodoro

3

यह मेरा कोड नहीं है, लेकिन यह मेरे लिए एक इलाज काम किया:

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

कॉपी पेस्ट:

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; } 
    } 
} 

जब मैं इसका इस्तेमाल मैं वापसी के नाम से इसे बदल कार्यपुस्तिका के संदर्भ में कार्यपुस्तिका।

संबंधित मुद्दे