Excel: 是否可以在不保护 sheet 的情况下将单元格设置为只读?

Excel: Can cells be made read only without protecting sheet?

这是一个有点小众的问题,因为通常 更适合保护 sheet,但我认为在某些情况下你只需要通过保护 Sheet 保护单元格的内容以避免意外编辑和删除,而不限制 sheet 作为一个整体的可编辑性,例如创建新过滤器。

我的问题:

我需要通过脚本将 Revit 明细表导出到 excel 传播sheet 进行编辑,然后导入回 Revit。这是因为编辑元素(尤其是房间)可能会增加我们项目规模的负担,并且缺乏在 Revit 明细表中排序和替换内容的直观和快速的方法。我创建了一个宏,它将 Excel 文件的完整路径(共享网络驱动器的 UNC 路径)等保存到配置文件中,基本上是“link” Excel 的时间表文件。如果在配置文件中找不到 excel 文件,那么我会通过 OpenFileDialog()CheckFileExists = false 创建一个文件,这样就出现了问题。

如果我创建一个新的Excel文件并在保存文件时使用Microsoft.Office.Interop.Excel方法sheet.Protect("password"),导出到新创建的文件的用户需要知道在哪里查看宏以解锁 sheet 以进行一些受保护的 sheet 不允许的设置。这也将允许他们有意或无意地更改任何受保护的数据,并损害数据的有效性。更糟糕的是,if/when 我有时间将它变成一个更发达的 Revit 插件而不是宏,使用的密码将被隐藏,不允许更值得信赖的高级用户设置 sheet。如果我允许用​​户在创建新 Excel 文件时设置密码,那么他们可以随时解锁它。

需求:

使用此脚本导出的数据除了 Revit 明细表中包含的内容外,还包含 Revit 元素的 ElementId,这是将 Excel 数据以 100% 准确度关联回 Revit 元素所必需的(这是元素存在时唯一不变的元素 属性)。如果以在 Excel 文件中创建重复值的方式对其进行更改,则导入的有效性将被破坏,并且需要回滚(此错误被忽视的时间越长,严重性越高)。

简单地隐藏 ElmentId 列不会阻止用户多管闲事取消隐藏它,并且 Protect Sheet 不允许在新的 Excel 文件时对 sheet 进行一小部分必要的更改已创建。

因此,我需要“防止”意外更改 ElementId 列,但仍允许更改 Protect Sheet 不允许的一小部分功能。

同样,我意识到这是非常小众的需求,通常不是保护数据所需的限制。我还意识到这与 Protect Sheet 一样无法防止行被删除。也就是说,我的目标是防止 Excel 中的 ElementId 值被编辑为另一个有效的 ElementId 值,仅此而已。因此,删除一行仅意味着与该特定 ElementId 关联的 Revit 元素在导入数据时不会收到任何形式的更新,因为该单元格为 null 被跳过或包含无效的 ElementId关联到现有元素,从而保护所述元素数据的有效性。

有两种解决方法。第一个是通过我自己的实验。第二个是产生的思路,感谢 Solar Mike 提醒我一个非常有用的功能,但由于缺乏使用(通常不需要它)而忘记了:非常隐藏 Sheets。他似乎建议的途径可能不会完全按照他的意图工作,理想情况下,这个 Revit 宏和 Excel 文件组合应该可供我公司的任何人使用,但有一种方法可以让它为任何人工作。以下是解决我的问题的两种方法,希望其他任何处于类似绑定但由于某种原因无法使用 Protect Sheet 来完成此工作的人。


解决方案 1:数据验证

通过设置 Allow: CustomFormula: "",我可以触发错误警报功能,并将样式设置为“停止”,这将禁止任何更改。

更好的是,如果我想禁止删除单元格数据,取消选中“忽略空白”框也会在按下单元格上的 Delete 键时出现错误警报。

将此与隐藏列结合使用会混淆编辑这些单元格的过程,通过大量步骤来启用编辑,从而阻止用户打扰单元格内容。

优点:

  • 可以利用输入消息警告用户更改单元格内容的危险
  • 可以使用错误警报彻底阻止数据输入或删除单元格内容
  • 在人们改变价值观之前需要额外的步骤,使用努力作为威慑

缺点:

  • 不针对以下情况提供保护(进一步阅读以了解详细信息 说明):
    • 删除行(通过在工作簿中使用 this 宏进行偏移 Visual Basic 编辑器)
    • 将另一个单元格复制并粘贴到只读单元格(处理 消除这个问题的宏)
    • 通过代码或宏改变单元格
  • 需要宏来缓解上述某些限制,这可以是 禁用并使数据面临概述问题的风险。
  • 需要额外的列(可以而且很可能应该隐藏) 您的数据,这对于那些查看列字母的人来说变得显而易见。
  • 不阻止人们关闭数据验证,如果有人 认为付出是值得的

删除行:

对于此解决方案,这对我来说并不重要,因为我正在逐行读取 excel 中的数据,使用 ElementId 单元格查找 Revit 元素。如果 Excel 行被删除,关联的 Revit 元素只会错过通过该导入获取数据,然后在下一次导出时从计划中重新添加到 Excel 文件中 运行,只要图元仍然存在于 Revit 中。但是如果在您的情况下需要维护行数据以避免数据损坏,您可以使用 linked 宏来禁用它。

代码改动:

至少外部代码;我还没有针对 Excel 中的 VBA 宏进行测试,但我假设也是如此。我认为这是因为数据验证是由用户在界面级别与单元格交互激活的,但是当使用 C# 中的 Microsoft.Office.Interop.Excel 库写入单元格时,您绕过了界面并直接与单元格数据,因此不会触发数据验证。我不担心由此产生的安全或验证问题,因为我们 AEC 公司中很少有人知道如何编码,而那些确实没有理由与这些文件交互的人 and/or 缺乏访问文件夹的权限(分离学科)。虽然在大多数情况下并不完美,但这是我能为我们当前的需求提出的最佳解决方案。

解决方案 2:非常隐蔽 Sheet

这个方法利用了Excel的两个特征:

  • 非常隐蔽sheet可见性设置

具体来说,我指的宏是解决方案 1 的 Con 部分中的 link,防止 Row/Column 删除。

解决方案是让您的脚本写入两个不同的 sheet,一个用于您的整体数据,另一个用于您的唯一标识符。这些的编写应该以这样一种方式进行编码,即在移动到下一行之前,您将在每个 sheet 中写入一行,以确保标识符和数据位于同一行并减少编辑时的错误以后的代码。

保存新生成的无格式无过滤器的Excel文件时,将标识符sheet的可见性设置为xlSheetVeryHidden,或2。此设置应作为作品sheet 属性 通过Interop.Excel 界面公开。这样,只有可以使用宏的高级用户才能取消隐藏 sheet,前提是他们知道要查找它。

优点:

  • 确保只有那些明确告知其存在的人才能访问唯一标识符,即便如此,也只有那些有能力或拥有访问它的工具的人才能访问
  • 通过使用防止删除行宏,标识符将始终与正确的数据配对,只要代码将数据正确写入 Excel
  • 通过消除 copy/paste 风险
  • 比数据验证更安全

缺点:

  • 需要将文件另存为 .xlsm 或启用宏的工作簿,根据贵公司的安全设置,这可能会向那些不熟悉为什么将文件设置为这种方式的人发出危险信号
  • 如果通过安全设置禁用宏,则无法保证数据的有效性,因为行删除保护将被禁用

最后的想法

虽然我更喜欢解决方案 2 及其提供的可用性,但出于良心我不能使用它。我们公司的 OOTB Excel 安装默认禁用宏,一些人认为它们对他们在文件中的任务不是必需的,只是忽略了文件顶部的警告。纯粹因为有人不想启用宏而导致数据泄露的风险太大了。

我还想补充一点:如果您的情况与我不完全相同,我不会轻易推荐任何一种解决方案。 Protect Sheet 是保护单元格数据的最强方式,并且不会禁止使用现有的 Sort/Filter 功能。由于办公室中可能使用我的宏(以及希望未来的插件)的人员的经验 and/or 知识水平,我仅将这些作为我的首选解决方案,并且认识到这两种方法都不是完美的防御。

如果有人有任何其他建议,我很高兴听到他们,我一定会更新这个答案if/when我有一个更好的解决方案版本。