Excel - 为什么命名合并范围与合并范围然后命名它不同?

时间:2016-03-22 14:16:23

标签: excel vba excel-vba named-ranges

我知道,我知道,合并范围很难处理。但无论如何:

我发现了一些有趣的行为,我可以复制/粘贴一些Merged Ranges而不是其他人。所以我做了实验。

设定:

enter image description here

enter image description here

很明显,这些范围并不是一回事。合并后命名的范围仅由topLeftCell引用组成,而命名后合并的范围保留对所有单元格的引用。

编辑:测试代码

Option Explicit

Public Sub PerformTests()

    Const NAME_THEN_MERGE As String = "Name_Then_Merge"
    Const MERGE_THEN_NAME As String = "Merge_Then_Name"
    Const PASTE_NAME_THEN_MERGE As String = "Paste_Name_Then_Merge"
    Const PASTE_MERGE_THEN_NAME As String = "Paste_Merge_Then_Name"

    TestNames MERGE_THEN_NAME, PASTE_NAME_THEN_MERGE
    '/ Result: Error 1004, cannot do that to a merged cell


End Sub

Public Sub TestNames(ByVal copyName As String, ByVal pasteName As String)

    wsPasteTest.Activate

    Dim copyRange As Range, pasteRange As Range
    Set copyRange = wsPasteTest.Range(copyName)
    Set pasteRange = wsPasteTest.Range(pasteName)

    CopyPasteCell copyRange, pasteRange

End Sub

Public Sub CopyPasteCell(ByRef copyCell As Range, ByRef pasteCell As Range, Optional ByVal pasteRowHeights As Boolean = False)

    copyCell.Copy
    pasteCell.PasteSpecial xlPasteAll

    If pasteRowHeights Then
        Dim sourceRowHeight As Long
        sourceRowHeight = copyCell.rowHeight
        pasteCell.rowHeight = sourceRowHeight
    End If

End Sub

经过大量测试后,这似乎是结论:

如果您命名一系列单元格然后合并它们,则指定的Range会保留对所有单元格的引用。如果先合并,则命名范围仅引用topLeftCell。

如果您尝试复制命名范围,则会将其视为与其'相同的大小。参考。因此,可以将一组(命名然后合并的)5个单元格复制到另一组相同大小的合并单元格或单个单元格中。

但是,(合并后命名)范围只能复制到单个单元格。尝试复制到一组5个合并的单元格将导致1004错误。

为什么呢?如何处理合并的单元格和命名范围导致这种差异?

供参考,这是Office 365,Excel版本15.0.4805.1003

1 个答案:

答案 0 :(得分:1)

我会对此进行一次尝试,因为我认为我已经对您的代码进行了足够的测试,以了解正在发生的事情。

让我们从Excel在执行您指定的操作时如何处理各种命名范围开始。您可以看到,在将copyRange设置为MERGE_THEN_NAME常量,并在新定义的.Copy上使用copyRange(用于测试目的)之后,A2单元格是在它周围有移动的虚线。

Option Explicit

Public Sub PerformTests()

    Const NAME_THEN_MERGE As String = "Name_Then_Merge"
    Const MERGE_THEN_NAME As String = "Merge_Then_Name"
    Const PASTE_NAME_THEN_MERGE As String = "Paste_Name_Then_Merge"
    Const PASTE_MERGE_THEN_NAME As String = "Paste_Merge_Then_Name"

    TestNames MERGE_THEN_NAME, PASTE_MERGE_THEN_NAME
    '/ Result: Error 1004, cannot do that to a merged cell


End Sub

Public Sub TestNames(ByVal copyName As String, ByVal pasteName As String)

    Sheets("wsPasteTest").Activate

    Dim copyRange As Range, pasteRange As Range
    Set copyRange = Sheets("wsPasteTest").Range(copyName)
    copyRange.Copy    'This is the last step executed before error
    Set pasteRange = Sheets("wsPasteTest").Range(pasteName)

    CopyPasteCell copyRange, pasteRange

End Sub

enter image description here

这是预期的,因为定义的范围在名称管理器中被读为=wsPasteTest!$A$2

Name Manager Description

范围的这个定义意味着当Excel重新访问命名范围以提取值时,它通过字面解释地址来实现,即它仅考虑自其the merged cells' value is defined in the "top left"单元格地址以来的A2的单元格值。通过需要使用Range("A2:E2").Cells(1).Value而不是简单Range("A2:E2").Value之类的东西,通过VBA过程(在上面的超链接中解决)返回合并单元格的值的正确方法可以确认此逻辑。后一个选项返回一个数组,因为它正在考虑范围内每个单元格的值。

下一部分是为什么在整个代码中使用.Select.Activate会很危险,同时也会说明如何获得您想要的行为。我们可以看到.Select copyCell选择整个合并单元格的时间A2.Copy方法中的copyCell进行比较(模仿用户与范围的交互方式)电子表格本身)。现在,如果我们选择Selection.Copy然后使用A2,则会复制整个合并的单元格,而不仅仅是PerformTests(),因为Excel已被指示抓取整个阵列区域。 Excel也刚刚展示了选择一个项目然后使用选择的重要性可以大大改变其对范围的解释,而不是明确地使用该范围。

TestNames()Public Sub CopyPasteCell(ByRef copyCell As Range, ByRef pasteCell As Range, Optional ByVal pasteRowHeights As Boolean = False) copyCell.Select Selection.Copy 'this step is shown in the first screenshot below pasteCell.Select Selection.PasteSpecial xlPasteAll 'this step is shown in the second screentshot below If pasteRowHeights Then Dim sourceRowHeight As Long sourceRowHeight = copyCell.RowHeight pasteCell.RowHeight = sourceRowHeight End If End Sub 中的代码与您的代码相同,以下子代码已修改:

copyCell

以下是pasteCell被选中,然后复制的结果。

Selection.Copy result

以下是Merge_Then_Name被选中,然后粘贴的结果。这会显示您在使用xlPasteValues范围时所需的结果。

selection.PastSpecial result

最终,您可以看到,当您明确指定已经在合并后定义的命名范围时,它会逐字地解释命名范围的地址(给出具有单个单元格格式的单个单元格值)显然不能使用建议的粘贴方法粘贴到所需的区域大小。 如果您将粘贴方法更改为.Select,则可以避免使用Paste_Merge_Then_Name 。这样做的原因是它允许=wsPasteTest!$A$8的定义保持为Public Sub CopyPasteCell(ByRef copyCell As Range, ByRef pasteCell As Range, Optional ByVal pasteRowHeights As Boolean = False) copyCell.Copy pasteCell.PasteSpecial xlPasteValues If pasteRowHeights Then Dim sourceRowHeight As Long sourceRowHeight = copyCell.RowHeight pasteCell.RowHeight = sourceRowHeight End If End Sub ,同时还允许将值传输到单个单元区域。此方法仅在替换值时保持目标单元格的格式相同。它不是你想要的粘贴,但非常接近。

Name_Then_Merge

PasteSpecial Result

.Copy范围适用于单个单元格和命名范围粘贴,主要原因之一;它包含多少占位符的值。当您执行Name_Then_Merge的{​​{1}}方法时,它会选择整个合并的单元格,因为它的定义是指示 =wsPasteTest!$A$5:$E$5。这很好,因为将它粘贴到相同大小的命名范围会起作用,因为它们匹配,并且粘贴到单个单元格中会起作用,因为只有一个非空白值。

摘要:命名范围由其初始单元格值定义,即使在合并单元格后也保留该数量的“位置”。因此,如果您命名范围,它将引用范围中每个单元格的值(在这种情况下为5个值),并且合并单元格不会更改命名范围的定义(但会在第一个更改后更改数组的所有值)单元格为“”作为占位符。如果合并单元格然后命名范围,则该值将保留在合并区域的左上角单元格中,因此将用作命名范围的合并单元格的定义。在这种情况下,如果您尝试将.PastexlPasteAll放入合并的单元格中,Excel会感到困惑,因为它会将源的值复制为单个单元格区域并尝试将其粘贴到目的地是一个五个小区。

通过选择它或使用不同的粘贴方法确保复制指定范围的整个区域来解决此问题,但要注意这些粘贴方法产生的内容。例如。 xlPasteAllUsingSourceTheme将取消合并目标单元格,但仍满足命名范围定义。