В Excel VSTO, как я могу проверить, принадлежит ли лист к закрытой книге? - PullRequest
5 голосов
/ 07 марта 2012

Если у меня есть ссылка на Worksheet, и я закрываю его родительский Workbook, ссылка не исчезает.Но я не могу понять, как я должен проверить, чтобы убедиться, что эти листы не существуют.Проверка на null не работает.

Пример:

Workbook book = Globals.ThisAddIn.Application.ActiveWorkbook;
Worksheet sheet = (Worksheet)book.Worksheets[1]; // Get first worksheet
book.Close(); // Close the workbook
bool isNull = sheet == null; // false, worksheet is not null
string name = sheet.Name; // throws a COM Exception

Это исключение, которое я получаю, когда пытаюсь получить доступ к листу:

System.Runtime.InteropServices.COMException was caught
  HResult=-2147221080
  Message=Exception from HRESULT: 0x800401A8
  Source=MyProject
  ErrorCode=-2147221080
  StackTrace:
       at Microsoft.Office.Interop.Excel._Worksheet.get_Name()
       at MyCode.test_Click(Object sender, RibbonControlEventArgs e) in c:\MyCode.cs:line 413
  InnerException: 

Это даже не было бы проблемой, если бы я мог проверить событие удаления книги, но Excel не предоставляет его (что действительно раздражает).

Есть ли какой-нибудь удобный способубедитесь, что я не пользуюсь этими листами?

Ответы [ 3 ]

3 голосов
/ 07 марта 2012

Я использую этот метод:

        private void releaseObject(object obj)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            obj = null;
        }
        catch (Exception ex)
        {
            obj = null;
            MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
        }
        finally
        {
            GC.Collect();
        }
    }

или вы можете попробовать что-то вроде этого:

    static bool IsOpened(string wbook) 
{ 
    bool isOpened = true; 
    Excel.Application exApp; 
    exApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"); 
    try 
    { 
        exApp.Workbooks.get_Item(wbook); 
    } 
    catch (Exception) 
    { 
        isOpened = false; 
    } 
    return isOpened; 
} 
3 голосов
/ 09 марта 2012

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

public void Test()
{
    Workbook book = Globals.ThisAddIn.Application.ActiveWorkbook;
    string wbkName = book.Name; //get and store the workbook name somewhere
    Worksheet sheet = (Worksheet)book.Worksheets[1]; // Get first worksheet
    book.Close(); // Close the workbook
    bool isNull = sheet == null; // false, worksheet is not null
    string name;

    if (WorkbookExists(wbkName))
    {
        name = sheet.Name; // will NOT throw a COM Exception
    }
}

private bool WorkbookExists(string name)
{
    foreach (Microsoft.Office.Interop.Excel.Workbook wbk in Globals.ThisAddIn.Application.Workbooks)
    {
        if (wbk.Name == name)
        {
            return true;
        }
    }

    return false;
}

Редактировать: для полноты, вспомогательный метод расширения:

public static bool SheetExists(this Excel.Workbook wbk, string sheetName)
{
    for (int i = 1; i <= wbk.Worksheets.Count; i++)
    {
        if (((Excel.Worksheet)wbk.Worksheets[i]).Name == sheetName)
        {
            return true;
        }
    }

    return false;
}
0 голосов
/ 07 марта 2012

Я не пробовал этого, но вы можете проверить, существует ли Рабочая книга sheet.Parent в коллекции Application.Workbooks.

...