5

I've got a very simple procedure that copies a range from one workbook and pastes it into another; the issue is, I'm getting the error in the title on the paste line.

Below is the code:

Sub copypasta()
Dim x As Workbook
Dim y As Workbook

Set x = ActiveWorkbook
Set y = Workbooks.Open("F:\Target\FTB\FTB.xlsx")

x.Sheets(1).Range("A1").CurrentRegion.Copy

y.Sheets("DTR").Cells.Delete '<~~~No Error Here...?
y.Sheets("DTR").[a1].Paste   '<~~~Error Here

I thought it was strange that the deletion works fine, but paste does not.

It seems that I may be missing some fundamentals of the paste method - could someone please explain what I'm missing here?

ThunderFrame
  • 9,352
  • 2
  • 29
  • 60
aLearningLady
  • 1,988
  • 4
  • 24
  • 42

4 Answers4

19

Other answers have provided ways to make it work, but don't explain what's going on.

y.Sheets("DTR")

That should really be y.Worksheets("DTR"), because the Sheets collection can contain non-worksheet items, such as charts for example.

Regardless, both the Sheets and the Worksheets collections' Item property (which is the default property of any collection type) yields an Object, which makes every chained member call that follows, a late-bound call.

And you don't get IntelliSense on late-bound calls, since these calls get resolved at run-time, by definition: you can call anything on an Object, and the code will happily compile:

Sub Test()
    Debug.Print ThisWorkbook.Worksheets(1).Whatever
End Sub

Same as:

Sub Test()
    Debug.Print ThisWorkbook.Worksheets.Item(1).Whatever
End Sub

At run-time, if VBA can't find the Whatever member on the retrieved object's interface, it raises run-time error 438, "Object doesn't support this property or method".

Late-binding is powerful and very useful, but it also incurs overhead that you don't necessarily need.

Instead of working off an Object, you can cast the returned object reference to a specific type when you know what that type is - in this case we know we're dealing with a Worksheet object:

Dim target As Worksheet
Set target = y.Worksheets("DTR")

Now that you have an early-bound Worksheet object reference, IntelliSense can guide you:

IntelliSense dropdown listing members of a Worksheet object

And if you try to call a bogus member (e.g. target.Whatever), you'll get a compile-time error instead of a run-time error.

compile error: member or data member not found

When you do this:

target.[A1].Paste

You're using late-binding again, to retrieve the A1 range. Instead, call the Worksheet.Range property getter to retrieve an early-bound Range object - and from there you'll see that when you type .paste there is no such thing as a Paste method in a Range object:

autocompletion for Range.PasteSpecial

And you get autocompletion and tooltips for everything as you type it:

XLPasteType enum members listed for first parameter of Range.PasteSpecial method

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
3

You can Copy and Paste Ranges between sheets (and workbooks) using 1 line of code, just replace your code with the line below:

x.Sheets(1).Range("A1").CurrentRegion.Copy y.Sheets("DTR").[a1] 

If you want to use the PasteSpecial method, you got to do it in 2 lines, but you need to add a parameter after the PasteSpecial , like xlValues, etc.

x.Sheets(1).Range("A1").CurrentRegion.Copy
y.Sheets("DTR").[a1].PasteSpecial xlValues
Shai Rado
  • 33,032
  • 6
  • 29
  • 51
  • 3
    Quick note, if you are just copying/pasting values, an alternative that avoids copy/paste is to just set he two ranges equal to each other: `Range([destination range]).value = Range([origin range]).value` – BruceWayne Nov 16 '16 at 19:53
  • 1
    @BruceWayne ...with an asterisk: `Range` implicitly referring to the active workbook, for it to work when the *destination* workbook isn't the *source* workbook, the `Range` calls need to be fully-qualified with a `Worksheet` reference. Well at least the *destination* range in this case. – Mathieu Guindon Nov 16 '16 at 20:06
  • @Mat'sMug - yes, great call especially when he's copying from sheet to sheet, I forgot to mention that. Thanks for catching! So, more specifically, it should be `y.Sheets("DTR").[a1].Value = x.Sheets(1).Range("A1").Value`. – BruceWayne Nov 16 '16 at 20:28
2

Change it to y.Sheets("DTR").[a1].PasteSpecial

Paste does not work on ranges, to paste a range you have to use PasteSpecial. I believe by default it does everything but you can specify quite a bit, see here

tjb1
  • 747
  • 9
  • 30
2

The problem with your original code was two-fold.

  1. The Cells.Delete statement appeared after the copy, but a delete action clears the clipboard.

  2. The Paste method is a member of the Sheet object, not the Range object.

Adjusting your code, that becomes:

y.Sheets("DTR").Cells.Delete
x.Sheets(1).Range("A1").CurrentRegion.Copy
y.Sheets("DTR").Paste y.Sheets("DTR").[a1]
aLearningLady
  • 1,988
  • 4
  • 24
  • 42
ThunderFrame
  • 9,352
  • 2
  • 29
  • 60