如何在Excel中保留Excel Ribbon Ribbon Addin的数据

我创build了一个Excelfunction区插件,它需要在Excel会话之间保留用户select。 使用自定义XML部件似乎是最好的select。 但是我不能得到这个工作没有得到COMExceptions。

MSDN文档不是很有用(http://msdn.microsoft.com/en-us/library/bb608612.aspx)。 有人可以给我一个在Excelfunction区插件中做这个工作的例子吗?

我知道有三种不同的方法:

自定义XML部分对于应用程序级别的添加,这是我首选的存储任何应用程序数据的方法,这些应用程序数据需要保存在保存的xls文件中,而不会被用户看到。

http://msdn.microsoft.com/en-us/library/bb608612.aspx

caching的数据岛这仅适用于文档级的添加。 如果您尝试在应用程序级别添加中使用它,您将会遇到exception。

http://blogs.msdn.com/b/eric_carter/archive/2004/04/23/119294.aspx

隐藏工作表使用VSTO,您可以创build用户无法看到的隐形工作表。 这很好,但导致了很多笨拙的编码来转换您的数据,以适应Excel表。

更新(2014年):所以最后定制XML部分的使用原来是一个性能问题,所以我的应用程序必须改回到使用隐藏的工作表。 显然,一旦XML达到一定的大小,Excel变得非常缓慢。 我的加载项自定义部分达到了数千个节点,而且XML越大,Excel中的所有内容越慢。 例如,简单地点击任何单元格会导致非常明显的延迟。

如果你想存储应用程序级插件中的任何一种元数据,你可以将数据串行化到某种string(base64,xml等),并保存在一个“非常隐藏”的表格中。 可见性设置为“非常隐藏”的工作表只能通过编程API访问,所以即使用户发现隐藏的工作表,他们仍然无法访问它,甚至不知道它在那里。

// create sheet for this save workbook.Sheets.Add(); newSettingsWorksheet = workbook.ActiveSheet; newSettingsWorksheet.Name = hiddenSheetName; newSettingsWorksheet.Visible = Excel.XlSheetVisibility.xlSheetVeryHidden; 

一个重要的事情要注意,如果你要存储的string长度超过32767个字符(适合在一个单元格中的字符的最大数量),那么你将不得不把它切成块,并分散在几个单元格。

关于您遇到的COMexception,您应该知道,如果任何时候遇到另一个COM对象(例如,工作表,单元格或属于Excel的任何东西),则Excel可以为任何请求抛出COMexception请求(例如,用户正在键入,它正在重新计算公式)。 您可以预期的例外是:

HRESULT:0x800AC472(忽略)

HRESULT:0x8000101A(稍后重试)

我猜Excel应用程序开发人员这样做,所以加载项不能让Excel本身看起来不好/无反应。

您应该使用registry来存储一些信息,例如用户首选项和历史logging,这些信息在应用程序closures后需要保留或需要在多个实例之间共享。

用户的configuration单元(HKEY_CURRENT_USER)永远不会有权限问题。 只需引用.NETregistry类: http : //msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx

考虑使用自定义属性。 每个Excel工作表在后台维护程序员容易使用的属性列表。 例如,我已经使用自定义属性来“记住”function区下拉列表中的哪些项目被选为特定工作表; 当工作表发生变化时,拉起该工作表的自定义属性,找出最后一次激活时下拉的项目。

自定义属性会保留每个表单和文档。

 using System; using Microsoft.Office.Interop.Excel; public partial class CustPropExample { /// <summary> /// delete and then store the custom property by passed key and value /// </summary> bool bExcelCustProp_Replace(Worksheet wkSheet, string custPropKey, string custPropVal) { if (!ExcelCustProp_DeleteByKey(wkSheet, custPropKey)) return (false); if (!ExcelCustProp_Add(wkSheet, custPropKey, custPropVal)) return (false); return (true); } /// <summary> /// return the custom property value of passed key /// </summary> string ExcelCustProp_Get(Worksheet wkSheet, string key) { try { for (int i = 1; i <= wkSheet.CustomProperties.Count; i++) // NOTE: 1-based !!!!!!!! { if (wkSheet.CustomProperties.get_Item(i).Name == key) return (wkSheet.CustomProperties.get_Item(i).Value); } } catch (Exception ex) { ShowErrorMsg("Error with getting cust prop; key [" + key + "], exc: " + ex.Message, false); } return (string.Empty); } /// <summary> /// add cust prop /// </summary> bool ExcelCustProp_Add(Worksheet wkSheet, string key, string custPropVal) { try { wkSheet.CustomProperties.Add(key, custPropVal); } catch (Exception ex) { return(ShowErrorMsg("Error in adding cust prop: " + ex.Message, false)); } return (true); } /// <summary> /// if passed key exists, delete it /// </summary> bool ExcelCustProp_DeleteByKey(Worksheet wkSheet, string key) { try { for (int i = 1; i <= wkSheet.CustomProperties.Count; i++) // NOTE: 1-based !!!!!!!! { if (wkSheet.CustomProperties.Item[i].Name == key) { wkSheet.CustomProperties.Item[i].Delete(); break; } } } catch (Exception ex) { return(ShowErrorMsg("Error deleting cust prop (key='" + key + "') - " + ex.Message, false)); } return (true); } /// <summary> /// stub for error handling /// </summary> bool ShowErrorMsg(string msg, bool retval) { System.Windows.Forms.MessageBox.Show(msg); return (retval); } }