Home » excel » excel – In VBA, how do I access the subject of a With statement from within that statement?

excel – In VBA, how do I access the subject of a With statement from within that statement?

Posted by: admin May 14, 2020 Leave a comment

Questions:

I am working on a quicker way to cycle through a column in a table in some previously written code. The problem I have is that at some point I need to assign the subject of the With statement (a single cell range) to an array of ranges, depending on the value of the range and nearby cells.

I have trimmed the code and taken only those bits which are necessary to the problem. See below:

Dim wb As Workbook
Dim wsFit As Worksheet
Dim fittingsTable As ListObject
ReDim fittings(0) As Range
Dim x As Integer
Dim y As Integer

Set wb = ActiveWorkbook
Set wsFit = wb.Worksheets("Fittings")
Set fittingsTable = wsFit.ListObjects("FittingsTable")

For x = 1 To fittingsTable.DataBodyRange.Rows.Count
  With fittingsTable.DataBodyRange(x, 15)
    If .Value <> vbNullString And .Value <> "0" Then
      If .Offset(0, -2).Value <> "TBC" Then
        'Do some stuff
        Set fittings(y) = 'PROBLEM HERE
      Else
        'Do other stuff here
      End If
    End If
  End With
Next

I want to assign fittingsTable.DataBodyRange(x, 15) to fittings(y), but I have no idea how to access the range that is the subject of the With statement.

I know that I could assign the desired range to another variable before the With statement begins, and then assign that variable to fittings(y) instead, but I feel like there must be a simple way to access the initial subject of the With statement so that I don’t end up clogging my code with yet more variables. I could also use the .Address property to assign the range using the worksheet, but at this point I’m genuinely curious about finding a more direct way.

How to&Answers:

Your With block is holding a Range object reference.

You can use the .Cells (parameterless) property to retrieve a reference to that Range object:

Set fittings(y) = .Cells

Or, to make it more explicit that it’s a single-cell range:

Set fittings(y) = .Cells(1, 1)

This makes an implicit default member call that ultimately ends up being equivalent to:

Set fittings(y) = .Item(1, 1)

That works for a Range. For a lot of other classes, there is no property that returns a reference to the object. For example, a Collection:

With New Collection
    .Add 42
    Set foo = ???? ' can't get a reference to the Collection object!
End With

The general solution is to extract the With block variable into a local variable, and now that variable is accessible just like any other local:

Dim c As Collection
Set c = New Collection
With c
    .Add 42
    Set foo = c
End With

For a custom class that you control, you can have a property getter that returns Me:

Public Property Get Self() As Class1
    Set Self = Me
End Property

And now the With block variable is accessible through that property:

With New Class1
    .Something = 42
    Set foo = .Self
End With