在VBA中,Rows属性有一种奇怪的行为

Ker*_*jus 2 excel vba excel-vba

我试图弄清楚如何在大范围内的特定行上工作.但是,使用rows属性创建的范围似乎与简单范围的行为不同.检查以下代码,第一次定义变量SpecificRow时,无法选择特定的单元格.然而,通过重新定义范围的奇怪解决方法,它工作正常.您是否知道为什么以及如何以更优雅的方式定义范围?

'The following shows the weird behavior of Rows property
Dim SourceRng As Range
Dim SpecificRow As Range
Dim i As Long

i = 3

Set SourceRng = Range("A1:D20")
Set SpecificRow = SourceRng.Rows(i)

'This will show the address of the selected row ("A3:D3")
MsgBox SpecificRow.Address

'Unexplicable behavior of the range when trying to select a specific cell
'where it will instead consider the whole row (within the limits of SourceRng)
MsgBox SpecificRow(1).Address
MsgBox SpecificRow(2).Address

'This would send an error
'MsgBox SpecificRow(1, 1).Address

'Workaround
Set SpecificRow = Intersect(SpecificRow, SpecificRow)

'The following will select the same address than before
MsgBox SpecificRow.Address

'However, now it has a correct behavior when selecting a specific cell
MsgBox SpecificRow(1).Address
MsgBox SpecificRow(2).Address
Run Code Online (Sandbox Code Playgroud)

Com*_*ern 5

如果您将索引属性传递给不正确的参数,则应该会出现奇怪的行为.正如您的代码所示,返回的Range SourceRng.Rows(i)实际上是正确的.它只是没有做你认为它正在做的事情.just 的Rows属性Range返回一个指向Range它所调用的完全相同对象的指针.您可以在其typelib定义中看到:

HRESULT _stdcall Rows([out, retval] Range** RHS);
Run Code Online (Sandbox Code Playgroud)

请注意,它不带任何参数.返回的Range对象是您为索引提供的索引,并且您正在根据它的默认属性对其进行索引Item(技术上它是_Default,但是2是可互换的).第一个参数(这是你传递的唯一参数Rows(i),是RowIndex.所以Rows(i)完全相同Rows.Item(RowIndex:=i).你可以在提供索引时弹出的IntelliSense工具提示中看到这个Row:

智能感知

Excel虽然在此调用上处理索引的方式不同,因为为第二个参数提供任何值参数是运行时错误"1004".请注意,调用时会进行类似的属性调用SpecificRow(1).Address.同样,默认属性RangeRange.Item(),因此您再次指定一行 - 而不是列.SpecificRow(1).Address是完全一样的SpecificRow.Item(RowIndex:=1).Address.

Excel中的奇怪似乎是Range返回Range.Rows"忘记"它在调用的上下文中被调用的事实Rows并且不再抑制列索引器.还记得从类型库定义的上方返回的对象只是一个指针回到原来的Range对象.这意味着从SpecificRow(2)泄密的背景中"泄漏".

考虑到所有事情,我会说Excel的Rows实现有点像黑客.Application.Intersect(SpecificRow, SpecificRow)显然是给你一个新的"硬"Range对象,但最后两行代码不是你应该考虑的"正确"行为.同样,当您只提供第一个参数时Range.Items,它被声明为RowIndex:

RowIndex在这里也是如此

什么似乎发生的是,Excel确定存在的只有一行Range在这一点上,只是假设传递的一个参数是一个ColumnIndex.

正如@CallumDA所指出的那样,您可以完全依赖默认属性并明确提供所需的所有索引,即:通过以下方式避免所有这些松散的行为:

Debug.Print SpecificRow.Item(1, 1).Address
'...or...
Debug.Print SpecificRow.Cells(1, 1).Address
Run Code Online (Sandbox Code Playgroud)