Copying the values of a filtered range to an array seems to work without a problem: the array then contains values from both filtered and unfiltered cells. However, when I copy the array’s contents back to the filtered range, the results are incomprehensible to me.
Here’s my code:
Sub test() Dim rangecopy() As Variant rangecopy() = Range(Cells(2, 1), Cells(14, 3)).Value For c = LBound(rangecopy, 1) To UBound(rangecopy, 1) rangecopy(c, 1) = c rangecopy(c, 2) = c * 10 rangecopy(c, 3) = c * 100 Next Range(Cells(2, 1), Cells(14, 3)).Value = rangecopy() End Sub
It is supposed to give the following result. Here, the range was unfiltered when the macro copied the array to it.
If the range is filtered by column D (“NO” is filtered out), the result looks like this:
First, the filtered cells aren’t updated. Then, most cells from column B get values from the array’s first column (4, 5, 6), while a few others get values from the array’s second column correctly (10). The last two rows are filled with #N/A error. Is this supposed to work that way? I’m using Office 2010.
I really hope someone with knowledge of the internal workings of VBA can provide more insight on your question. I can share the following:
First, it is working as intended. However, I don’t know why this is the design, nor what exactly is happening in the assignment process.
There are many cases that create a similar issue. For instance, if you have the filter on (some rows are hidden) and try to fill (drag) a formula down, you will see similar results, in that hidden rows aren’t populated, but they do affect the (relative) references in the formula. On the other hand, if you manually copy and paste into a filtered range, the data is pasted into the hidden rows (as you intend).
It seems that any range referenced that is part of the Autofilter range is actually non-contiguous*. Using Range.Address does not always reveal this, nor does looping through Range.Areas. If we modify your example, we can see where the “real” error is:
Dim r1 as range Dim r2 as range Set r1 = Sheet1.Range("A1:B5") 'some numbers in a range Set r2 = Sheet2.Range("A2:B6") 'same-size range underneath a filtered header r1.Copy Destination:=r2
It works when all the rows are visible. When the filter on Sheet2 creates hidden rows, the result is “Run-time error ‘1004’: …the Copy area and the paste area are not the same size and shape.” On the other hand, using the “manual” / clipboard method works for hidden rows:
r1.Copy r2.PasteSpecial (xlPasteValues)
Since assigning an array to a range bypasses the clipboard (as in the 1st block), we ought to receive an error (instead you just end up with erroneous results).
The only solutions I’m aware of are to either loop through the range and assign a value to each cell:
For i = 1 to LastRow For j = 1 to LastCol Sheet1.Cells(i,j).Value = myArr(i,j) Next Next
OR (better) remove the Autofilter, assign the array to the range, then reapply the filter.
*technically it’s contiguous, so it may be better to say that the range is composed of several ranges/areas, although using .Address doesn’t indicate this and there is only one area when you try to loop through Range.Areas