2012-03-06 22 views
5

Si tengo una referencia a Worksheet y cierro es el padre Workbook, la referencia no desaparece. Pero no puedo entender cómo debo verificar para asegurarme de que estas hojas no existan. La comprobación de null no funciona.En Excel VSTO, ¿cómo puedo verificar si una hoja de trabajo pertenece a un libro cerrado?

Ejemplo:

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 

Ésta es la excepción que consigo cuando intento acceder a la ficha técnica:

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: 

Esto ni siquiera sería un problema si podía comprobar si hay un libro de eliminar evento, pero Excel no proporciona uno (que es realmente molesto).

¿Hay alguna manera conveniente de asegurarme de no utilizar estas hojas de trabajo?

Respuesta

3

Si las otras soluciones fallan, otra manera de manejar esto es para almacenar el nombre del libro después de que se abra, luego verifique si ese nombre existe en la colección Workbooks antes de hacer referencia a la hoja. Hacer referencia a los libros de trabajo por nombre funcionará desde you can only have uniquely named workbooks in each instance of 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; 
} 

Editar: para lo completo, un método de extensión ayudante:

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

Esto funciona, pero solo si tengo el 'Libro de trabajo' en ese momento. Mi código de ejemplo fue simple, pero en la práctica, tengo varios métodos que solo toman un objeto 'Hoja de trabajo'. Sin embargo, voy a aceptar tu respuesta ya que terminé haciendo algo similar. A saber, revisé 'Application.Workbooks.Count> 0'. Como solo me encontré con este problema cuando no había libros abiertos, este cheque fue suficiente para mis necesidades. Gracias por tu aporte. –

0

No he intentado esto, pero podría verificar si el Libro de trabajo sheet.Parent existe en la colección Application.Workbooks.

+0

no funcionará. Llamar 'sheet.Parent' causa la misma excepción que llamar' sheet.Name'. Buena idea sin embargo. –

3

que utiliza este método:

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

o puede intentar algo como esto:

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

¿Cómo sé cuándo llamar esto? Tengo una hoja de trabajo potencialmente abierta o potencialmente cerrada. Si está abierto, quiero hacer algo con él. Si está cerrado, no. El problema es que no tengo manera de saber si está abierto o cerrado. Este método parece ayudar solo si sé que está cerrado. –

+0

Agregué código adicional. – Andrew

+0

Puedo hacer esto, pero prefiero usarlo como último recurso. En general opino que [las excepciones no se deben usar para controlar el flujo]. (Http://stackoverflow.com/questions/729379/why-not-use-exceptions-as-regular-flow-of-control) –

Cuestiones relacionadas