Skip to main content
Revised after further testing of Range.SpecialCells
Source Link

This is mostly just a stylistic preference, but if I were implementing thisEDIT: Actually, I probably wouldn't want to return Null. I'd prefer some sort of optional parameterit turns out that alters how the function treats ranges with a mix of validation/no validationRange. Here's what that'd look like:

Function hasValidation(rng As Range, Optional entireRange As Boolean = False) As Boolean
    
    '...
    'Both versions are the same up to this line
    
    'Determine whether entire/partial range has validation and return value
    If rngUnion Is Nothing Then
        hasValidation = False
    ElseIf rngUnion.Count = rng.Count Then
        hasValidation = True
    Else
        hasValidation = Not entireRange
    End If
    
End Function

EDIT: Turns out the SpecialCells method for finding empty cellsSpecialCells(xlCellTypeBlanks) is way worse than I thought. Not only is it obscenely slow if your worksheet contains a lot of datafor large ranges, it also only searches the Used Range, not the entire sheet. So If you need to avoid "On Error" statements, I'd recommend using a helper functionmay have no option but to find the empty cell, which would only use the SpecialCells method as a last resorterror handling. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function

It's also possible toLuckily, you can use the same basic format while incorporating On Error. Since it uses Intersect instead of looping through cells, it should be faster than your version. Also, rather than returning Null in mixed cases, it uses optional parameter that alters how the function treats ranges with a mix of validation/no validation. That's just a stylistic preference, I'm not a big fan of Null. Here's my final version:

This is mostly just a stylistic preference, but if I were implementing this, I probably wouldn't want to return Null. I'd prefer some sort of optional parameter that alters how the function treats ranges with a mix of validation/no validation. Here's what that'd look like:

Function hasValidation(rng As Range, Optional entireRange As Boolean = False) As Boolean
    
    '...
    'Both versions are the same up to this line
    
    'Determine whether entire/partial range has validation and return value
    If rngUnion Is Nothing Then
        hasValidation = False
    ElseIf rngUnion.Count = rng.Count Then
        hasValidation = True
    Else
        hasValidation = Not entireRange
    End If
    
End Function

EDIT: Turns out the SpecialCells method for finding empty cells is obscenely slow if your worksheet contains a lot of data. So If you need to avoid "On Error" statements, I'd recommend using a helper function to find the empty cell, which would only use the SpecialCells method as a last resort. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function

It's also possible to use the same basic format while incorporating On Error. Since it uses Intersect instead of looping through cells, it should be faster than your version:

EDIT: Actually, it turns out that Range.SpecialCells(xlCellTypeBlanks) is way worse than I thought. Not only is it obscenely slow for large ranges, it also only searches the Used Range, not the entire sheet. So you may have no option but to use error handling.

Luckily, you can use the same basic format while incorporating On Error. Since it uses Intersect instead of looping through cells, it should be faster than your version. Also, rather than returning Null in mixed cases, it uses optional parameter that alters how the function treats ranges with a mix of validation/no validation. That's just a stylistic preference, I'm not a big fan of Null. Here's my final version:

added 1231 characters in body
Source Link

EDIT: Turns out the SpecialCells method for finding empty cells is obscenely slow if your worksheet contains a lot of data. So If you need to avoid "On Error" statements, I'd recommend using a helper function to find the empty cell, which would only use the SpecialCells method as a last resort. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function

It's also possible to use the same basic format while incorporating On Error. Since it uses Intersect instead of looping through cells, it should be faster than your version:

Function hasValidation(rng As Range, Optional entireRange As Boolean = False) As Boolean

    'Get range of all cells in sheet containing validation
    On Error Resume Next
    Dim validationCells As Range
    Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
    On Error GoTo 0
    
    'If no cells contain validation, return False and exit
    If validationCells Is Nothing Then
        hasValidation = False
        Exit Function
    End If
    
    'Get intersection of validation cells and range being tested
    Dim rngUnion As Range
    Set rngUnion = Intersect(rng, validationCells)
    
    'Determine whether entire/partial range has validation and return value
    If rngUnion Is Nothing Then
        hasValidation = False
    Else
        hasValidation = IIf(rngUnion.Count = rng.Count, True, Not entireRange)
    End If
    
End Function

EDIT: Turns out the SpecialCells method for finding empty cells is obscenely slow if your worksheet contains a lot of data. So I'd recommend using a helper function to find the empty cell, which would only use the SpecialCells method as a last resort. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function

EDIT: Turns out the SpecialCells method for finding empty cells is obscenely slow if your worksheet contains a lot of data. So If you need to avoid "On Error" statements, I'd recommend using a helper function to find the empty cell, which would only use the SpecialCells method as a last resort. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function

It's also possible to use the same basic format while incorporating On Error. Since it uses Intersect instead of looping through cells, it should be faster than your version:

Function hasValidation(rng As Range, Optional entireRange As Boolean = False) As Boolean

    'Get range of all cells in sheet containing validation
    On Error Resume Next
    Dim validationCells As Range
    Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
    On Error GoTo 0
    
    'If no cells contain validation, return False and exit
    If validationCells Is Nothing Then
        hasValidation = False
        Exit Function
    End If
    
    'Get intersection of validation cells and range being tested
    Dim rngUnion As Range
    Set rngUnion = Intersect(rng, validationCells)
    
    'Determine whether entire/partial range has validation and return value
    If rngUnion Is Nothing Then
        hasValidation = False
    Else
        hasValidation = IIf(rngUnion.Count = rng.Count, True, Not entireRange)
    End If
    
End Function
added 980 characters in body
Source Link

EDIT: Turns out the SpecialCells method for finding empty cells is obscenely slow if your worksheet contains a lot of data. So I'd recommend using a helper function to find the empty cell, which would only use the SpecialCells method as a last resort. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function

EDIT: Turns out the SpecialCells method for finding empty cells is obscenely slow if your worksheet contains a lot of data. So I'd recommend using a helper function to find the empty cell, which would only use the SpecialCells method as a last resort. Something like this:

Function getEmptyCell(ws As Worksheet) As Range

    Dim rng As Range
    Dim colNum As Long
    Dim rowNum As Long
    Set rng = ws.UsedRange
    colNum = rng.Cells(1, rng.Columns.Count).Column + 1
    rowNum = rng.Cells(rng.Rows.Count, 1).Row + 1
    
    If colNum > ws.Columns.Count Then
        If rowNum > ws.Rows.Count Then
            Set getEmptyCell = ws.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        Else
            colNum = colNum - 1
        End If
    ElseIf rowNum > ws.Rows.Count Then
        rowNum = rowNum - 1
    End If
    
    Set getEmptyCell = ws.Cells(rowNum, colNum)

End Function
added 44 characters in body
Source Link
Loading
Source Link
Loading