Check if a range in Excel contains DataValidation

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












One of the answers to Determine if cell contains data validation
got me thinking about an edge case I needed to solve. If cell happens to be a multi-cell range what's the best way to answer? The answer below returns False if the range contains both a cell with and without validation.



Function HasValidation(cell As Range) As Boolean
Dim t: t = Null

On Error Resume Next
t = cell.Validation.Type
On Error GoTo 0

HasValidation = Not IsNull(t)
End Function


The answer I arrived at allows for non-contiguous ranges. I chose Variant as the return type in the case that there's a mix of validated and non-validated cells. Since it's neither True nor False a Null seemed the best fit.



Public Function HasValidation(ByVal cell As Range) As Variant
Dim tempVariable As Variant
If cell.Cells.Count > 1 Then
On Error Resume Next

Dim singleCell As Range
For Each singleCell In cell
Debug.Print singleCell.Address(True, True)
tempVariable = Empty
tempVariable = singleCell.Validation.Type

If IsEmpty(tempVariable) Then
Dim cellWithoutValidationFound As Boolean
cellWithoutValidationFound = True
Else
Dim cellWithValidationFound As Boolean
cellWithValidationFound = True
End If

If cellWithValidationFound And cellWithoutValidationFound Then
On Error GoTo 0
HasValidation = Null
Exit Function
End If
Next

HasValidation = cellWithValidationFound
Else
tempVariable = Null
tempVariable = cell.Validation.Type
HasValidation = IsNull(tempVariable)
End If
End Function






share|improve this question



















  • No. I was focusing on the multi-cell option that I neglected to properly update a single-cell range.
    – IvenBach
    Apr 26 at 0:52
















up vote
2
down vote

favorite












One of the answers to Determine if cell contains data validation
got me thinking about an edge case I needed to solve. If cell happens to be a multi-cell range what's the best way to answer? The answer below returns False if the range contains both a cell with and without validation.



Function HasValidation(cell As Range) As Boolean
Dim t: t = Null

On Error Resume Next
t = cell.Validation.Type
On Error GoTo 0

HasValidation = Not IsNull(t)
End Function


The answer I arrived at allows for non-contiguous ranges. I chose Variant as the return type in the case that there's a mix of validated and non-validated cells. Since it's neither True nor False a Null seemed the best fit.



Public Function HasValidation(ByVal cell As Range) As Variant
Dim tempVariable As Variant
If cell.Cells.Count > 1 Then
On Error Resume Next

Dim singleCell As Range
For Each singleCell In cell
Debug.Print singleCell.Address(True, True)
tempVariable = Empty
tempVariable = singleCell.Validation.Type

If IsEmpty(tempVariable) Then
Dim cellWithoutValidationFound As Boolean
cellWithoutValidationFound = True
Else
Dim cellWithValidationFound As Boolean
cellWithValidationFound = True
End If

If cellWithValidationFound And cellWithoutValidationFound Then
On Error GoTo 0
HasValidation = Null
Exit Function
End If
Next

HasValidation = cellWithValidationFound
Else
tempVariable = Null
tempVariable = cell.Validation.Type
HasValidation = IsNull(tempVariable)
End If
End Function






share|improve this question



















  • No. I was focusing on the multi-cell option that I neglected to properly update a single-cell range.
    – IvenBach
    Apr 26 at 0:52












up vote
2
down vote

favorite









up vote
2
down vote

favorite











One of the answers to Determine if cell contains data validation
got me thinking about an edge case I needed to solve. If cell happens to be a multi-cell range what's the best way to answer? The answer below returns False if the range contains both a cell with and without validation.



Function HasValidation(cell As Range) As Boolean
Dim t: t = Null

On Error Resume Next
t = cell.Validation.Type
On Error GoTo 0

HasValidation = Not IsNull(t)
End Function


The answer I arrived at allows for non-contiguous ranges. I chose Variant as the return type in the case that there's a mix of validated and non-validated cells. Since it's neither True nor False a Null seemed the best fit.



Public Function HasValidation(ByVal cell As Range) As Variant
Dim tempVariable As Variant
If cell.Cells.Count > 1 Then
On Error Resume Next

Dim singleCell As Range
For Each singleCell In cell
Debug.Print singleCell.Address(True, True)
tempVariable = Empty
tempVariable = singleCell.Validation.Type

If IsEmpty(tempVariable) Then
Dim cellWithoutValidationFound As Boolean
cellWithoutValidationFound = True
Else
Dim cellWithValidationFound As Boolean
cellWithValidationFound = True
End If

If cellWithValidationFound And cellWithoutValidationFound Then
On Error GoTo 0
HasValidation = Null
Exit Function
End If
Next

HasValidation = cellWithValidationFound
Else
tempVariable = Null
tempVariable = cell.Validation.Type
HasValidation = IsNull(tempVariable)
End If
End Function






share|improve this question











One of the answers to Determine if cell contains data validation
got me thinking about an edge case I needed to solve. If cell happens to be a multi-cell range what's the best way to answer? The answer below returns False if the range contains both a cell with and without validation.



Function HasValidation(cell As Range) As Boolean
Dim t: t = Null

On Error Resume Next
t = cell.Validation.Type
On Error GoTo 0

HasValidation = Not IsNull(t)
End Function


The answer I arrived at allows for non-contiguous ranges. I chose Variant as the return type in the case that there's a mix of validated and non-validated cells. Since it's neither True nor False a Null seemed the best fit.



Public Function HasValidation(ByVal cell As Range) As Variant
Dim tempVariable As Variant
If cell.Cells.Count > 1 Then
On Error Resume Next

Dim singleCell As Range
For Each singleCell In cell
Debug.Print singleCell.Address(True, True)
tempVariable = Empty
tempVariable = singleCell.Validation.Type

If IsEmpty(tempVariable) Then
Dim cellWithoutValidationFound As Boolean
cellWithoutValidationFound = True
Else
Dim cellWithValidationFound As Boolean
cellWithValidationFound = True
End If

If cellWithValidationFound And cellWithoutValidationFound Then
On Error GoTo 0
HasValidation = Null
Exit Function
End If
Next

HasValidation = cellWithValidationFound
Else
tempVariable = Null
tempVariable = cell.Validation.Type
HasValidation = IsNull(tempVariable)
End If
End Function








share|improve this question










share|improve this question




share|improve this question









asked Apr 17 at 23:26









IvenBach

907314




907314











  • No. I was focusing on the multi-cell option that I neglected to properly update a single-cell range.
    – IvenBach
    Apr 26 at 0:52
















  • No. I was focusing on the multi-cell option that I neglected to properly update a single-cell range.
    – IvenBach
    Apr 26 at 0:52















No. I was focusing on the multi-cell option that I neglected to properly update a single-cell range.
– IvenBach
Apr 26 at 0:52




No. I was focusing on the multi-cell option that I neglected to properly update a single-cell range.
– IvenBach
Apr 26 at 0:52










2 Answers
2






active

oldest

votes

















up vote
1
down vote













I'd recommend caution re: using On Error statements in utility functions like this. Any custom error handling in the main procedure (ie "On Error GoTo lineNum") will be overwritten by this function, so you'll have to remember to manually change it back any time you use the function in a procedure with custom error handling.



My advice would be to pick a personal rule-- either "Never use On Error statements in utility functions, only in main procedures" or "Only use On Error statements in utility functions, never in main procedures"-- and stick to it.



If you do use them, make sure that you switch back to On Error GoTo 0 for all exits from the function. In the first portion of the "IF" block in your current code, you only switch back if the function returns null:



On Error Resume Next
Dim singleCell As Range
For Each singleCell In cell
'...do stuff, then

If cellWithValidationFound And cellWithoutValidationFound Then
On Error GoTo 0
HasValidation = Null
Exit Function
End If
Next

'On Error GoTo 0 needs to be added here
HasValidation = cellWithValidationFound


In this case, it's possible to avoid the "On Error" statements entirely by using the SpecialCells and Intersect methods. Only caveat is that it assumes that your range's parent worksheet contains at least one blank cell:



Function hasValidation(rng As Range) As Variant

'Find first empty cell in ws and add validation
'This ensures that at least 1 cell in ws contains validation
Dim emptyCell As Range
Set emptyCell = rng.Parent.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
emptyCell.Validation.Add Type:=xlValidateList, Formula1:="1"

'Get range of all cells in ws with validation, then remove validation from empty cell
Dim validationCells As Range
Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
emptyCell.Validation.Delete

'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
ElseIf rngUnion.Count = rng.Count Then
hasValidation = True
Else
hasValidation = Null
End If

End Function


It'd be possible to design a slightly safer version that accounts for sheets with no blank cells, but that scenario is so unlikely that it's probably not worth the effort.



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:



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





share|improve this answer






























    up vote
    0
    down vote













    I would suggest that HasValidation() returns either True or False, not maybe?...




    Option Explicit

    Public Function HasValidation(ByVal rng As Range) As Boolean
    Dim itHas As Boolean, eID As Long, eSRC As String, eDESC As String

    If Err.Number <> 0 Then
    eID = Err.Number
    eSRC = Err.Source
    eDESC = Err.Description
    Err.Clear
    End If

    On Error Resume Next
    If Not rng Is Nothing Then
    itHas = Not Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng) Is Nothing
    End If

    If Err.Number <> 0 Or eID <> 0 Then
    If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
    End If
    HasValidation = itHas
    End Function



    Or GetValidationRange() that returns a Range or Nothing




    Public Function GetValidationRange(ByVal rng As Range) As Range
    Dim vRng As Range, eID As Long, eSRC As String, eDESC As String

    If Err.Number <> 0 Then
    eID = Err.Number
    eSRC = Err.Source
    eDESC = Err.Description
    Err.Clear
    End If

    On Error Resume Next
    If Not rng Is Nothing Then
    Set vRng = Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng)
    End If

    If Err.Number <> 0 Or eID <> 0 Then
    If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
    End If
    Set GetValidationRange = vRng
    End Function



    .



    In your code



    • The parameter name (cell) implies that it expects a single cell

    • The Null return type can cause issues (not very used in normal operations)

    • As a user of the function I don't really know what to do with the result

      • Should I be looking some more for cells with validation or not?



    Edit



    @DanielMcCracken has a valid point about changing the error chain



    • I updated the answer to preserve the previous error





    share|improve this answer























      Your Answer




      StackExchange.ifUsing("editor", function ()
      return StackExchange.using("mathjaxEditing", function ()
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      );
      );
      , "mathjax-editing");

      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "196"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );








       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192335%2fcheck-if-a-range-in-excel-contains-datavalidation%23new-answer', 'question_page');

      );

      Post as a guest






























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      1
      down vote













      I'd recommend caution re: using On Error statements in utility functions like this. Any custom error handling in the main procedure (ie "On Error GoTo lineNum") will be overwritten by this function, so you'll have to remember to manually change it back any time you use the function in a procedure with custom error handling.



      My advice would be to pick a personal rule-- either "Never use On Error statements in utility functions, only in main procedures" or "Only use On Error statements in utility functions, never in main procedures"-- and stick to it.



      If you do use them, make sure that you switch back to On Error GoTo 0 for all exits from the function. In the first portion of the "IF" block in your current code, you only switch back if the function returns null:



      On Error Resume Next
      Dim singleCell As Range
      For Each singleCell In cell
      '...do stuff, then

      If cellWithValidationFound And cellWithoutValidationFound Then
      On Error GoTo 0
      HasValidation = Null
      Exit Function
      End If
      Next

      'On Error GoTo 0 needs to be added here
      HasValidation = cellWithValidationFound


      In this case, it's possible to avoid the "On Error" statements entirely by using the SpecialCells and Intersect methods. Only caveat is that it assumes that your range's parent worksheet contains at least one blank cell:



      Function hasValidation(rng As Range) As Variant

      'Find first empty cell in ws and add validation
      'This ensures that at least 1 cell in ws contains validation
      Dim emptyCell As Range
      Set emptyCell = rng.Parent.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
      emptyCell.Validation.Add Type:=xlValidateList, Formula1:="1"

      'Get range of all cells in ws with validation, then remove validation from empty cell
      Dim validationCells As Range
      Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
      emptyCell.Validation.Delete

      '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
      ElseIf rngUnion.Count = rng.Count Then
      hasValidation = True
      Else
      hasValidation = Null
      End If

      End Function


      It'd be possible to design a slightly safer version that accounts for sheets with no blank cells, but that scenario is so unlikely that it's probably not worth the effort.



      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:



      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





      share|improve this answer



























        up vote
        1
        down vote













        I'd recommend caution re: using On Error statements in utility functions like this. Any custom error handling in the main procedure (ie "On Error GoTo lineNum") will be overwritten by this function, so you'll have to remember to manually change it back any time you use the function in a procedure with custom error handling.



        My advice would be to pick a personal rule-- either "Never use On Error statements in utility functions, only in main procedures" or "Only use On Error statements in utility functions, never in main procedures"-- and stick to it.



        If you do use them, make sure that you switch back to On Error GoTo 0 for all exits from the function. In the first portion of the "IF" block in your current code, you only switch back if the function returns null:



        On Error Resume Next
        Dim singleCell As Range
        For Each singleCell In cell
        '...do stuff, then

        If cellWithValidationFound And cellWithoutValidationFound Then
        On Error GoTo 0
        HasValidation = Null
        Exit Function
        End If
        Next

        'On Error GoTo 0 needs to be added here
        HasValidation = cellWithValidationFound


        In this case, it's possible to avoid the "On Error" statements entirely by using the SpecialCells and Intersect methods. Only caveat is that it assumes that your range's parent worksheet contains at least one blank cell:



        Function hasValidation(rng As Range) As Variant

        'Find first empty cell in ws and add validation
        'This ensures that at least 1 cell in ws contains validation
        Dim emptyCell As Range
        Set emptyCell = rng.Parent.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
        emptyCell.Validation.Add Type:=xlValidateList, Formula1:="1"

        'Get range of all cells in ws with validation, then remove validation from empty cell
        Dim validationCells As Range
        Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
        emptyCell.Validation.Delete

        '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
        ElseIf rngUnion.Count = rng.Count Then
        hasValidation = True
        Else
        hasValidation = Null
        End If

        End Function


        It'd be possible to design a slightly safer version that accounts for sheets with no blank cells, but that scenario is so unlikely that it's probably not worth the effort.



        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:



        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





        share|improve this answer

























          up vote
          1
          down vote










          up vote
          1
          down vote









          I'd recommend caution re: using On Error statements in utility functions like this. Any custom error handling in the main procedure (ie "On Error GoTo lineNum") will be overwritten by this function, so you'll have to remember to manually change it back any time you use the function in a procedure with custom error handling.



          My advice would be to pick a personal rule-- either "Never use On Error statements in utility functions, only in main procedures" or "Only use On Error statements in utility functions, never in main procedures"-- and stick to it.



          If you do use them, make sure that you switch back to On Error GoTo 0 for all exits from the function. In the first portion of the "IF" block in your current code, you only switch back if the function returns null:



          On Error Resume Next
          Dim singleCell As Range
          For Each singleCell In cell
          '...do stuff, then

          If cellWithValidationFound And cellWithoutValidationFound Then
          On Error GoTo 0
          HasValidation = Null
          Exit Function
          End If
          Next

          'On Error GoTo 0 needs to be added here
          HasValidation = cellWithValidationFound


          In this case, it's possible to avoid the "On Error" statements entirely by using the SpecialCells and Intersect methods. Only caveat is that it assumes that your range's parent worksheet contains at least one blank cell:



          Function hasValidation(rng As Range) As Variant

          'Find first empty cell in ws and add validation
          'This ensures that at least 1 cell in ws contains validation
          Dim emptyCell As Range
          Set emptyCell = rng.Parent.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
          emptyCell.Validation.Add Type:=xlValidateList, Formula1:="1"

          'Get range of all cells in ws with validation, then remove validation from empty cell
          Dim validationCells As Range
          Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
          emptyCell.Validation.Delete

          '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
          ElseIf rngUnion.Count = rng.Count Then
          hasValidation = True
          Else
          hasValidation = Null
          End If

          End Function


          It'd be possible to design a slightly safer version that accounts for sheets with no blank cells, but that scenario is so unlikely that it's probably not worth the effort.



          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:



          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





          share|improve this answer















          I'd recommend caution re: using On Error statements in utility functions like this. Any custom error handling in the main procedure (ie "On Error GoTo lineNum") will be overwritten by this function, so you'll have to remember to manually change it back any time you use the function in a procedure with custom error handling.



          My advice would be to pick a personal rule-- either "Never use On Error statements in utility functions, only in main procedures" or "Only use On Error statements in utility functions, never in main procedures"-- and stick to it.



          If you do use them, make sure that you switch back to On Error GoTo 0 for all exits from the function. In the first portion of the "IF" block in your current code, you only switch back if the function returns null:



          On Error Resume Next
          Dim singleCell As Range
          For Each singleCell In cell
          '...do stuff, then

          If cellWithValidationFound And cellWithoutValidationFound Then
          On Error GoTo 0
          HasValidation = Null
          Exit Function
          End If
          Next

          'On Error GoTo 0 needs to be added here
          HasValidation = cellWithValidationFound


          In this case, it's possible to avoid the "On Error" statements entirely by using the SpecialCells and Intersect methods. Only caveat is that it assumes that your range's parent worksheet contains at least one blank cell:



          Function hasValidation(rng As Range) As Variant

          'Find first empty cell in ws and add validation
          'This ensures that at least 1 cell in ws contains validation
          Dim emptyCell As Range
          Set emptyCell = rng.Parent.Cells.SpecialCells(xlCellTypeBlanks).Cells(1)
          emptyCell.Validation.Add Type:=xlValidateList, Formula1:="1"

          'Get range of all cells in ws with validation, then remove validation from empty cell
          Dim validationCells As Range
          Set validationCells = rng.Parent.Cells.SpecialCells(xlCellTypeAllValidation)
          emptyCell.Validation.Delete

          '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
          ElseIf rngUnion.Count = rng.Count Then
          hasValidation = True
          Else
          hasValidation = Null
          End If

          End Function


          It'd be possible to design a slightly safer version that accounts for sheets with no blank cells, but that scenario is so unlikely that it's probably not worth the effort.



          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:



          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






          share|improve this answer















          share|improve this answer



          share|improve this answer








          edited Apr 19 at 15:45


























          answered Apr 18 at 17:09









          Daniel McCracken

          231112




          231112






















              up vote
              0
              down vote













              I would suggest that HasValidation() returns either True or False, not maybe?...




              Option Explicit

              Public Function HasValidation(ByVal rng As Range) As Boolean
              Dim itHas As Boolean, eID As Long, eSRC As String, eDESC As String

              If Err.Number <> 0 Then
              eID = Err.Number
              eSRC = Err.Source
              eDESC = Err.Description
              Err.Clear
              End If

              On Error Resume Next
              If Not rng Is Nothing Then
              itHas = Not Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng) Is Nothing
              End If

              If Err.Number <> 0 Or eID <> 0 Then
              If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
              End If
              HasValidation = itHas
              End Function



              Or GetValidationRange() that returns a Range or Nothing




              Public Function GetValidationRange(ByVal rng As Range) As Range
              Dim vRng As Range, eID As Long, eSRC As String, eDESC As String

              If Err.Number <> 0 Then
              eID = Err.Number
              eSRC = Err.Source
              eDESC = Err.Description
              Err.Clear
              End If

              On Error Resume Next
              If Not rng Is Nothing Then
              Set vRng = Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng)
              End If

              If Err.Number <> 0 Or eID <> 0 Then
              If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
              End If
              Set GetValidationRange = vRng
              End Function



              .



              In your code



              • The parameter name (cell) implies that it expects a single cell

              • The Null return type can cause issues (not very used in normal operations)

              • As a user of the function I don't really know what to do with the result

                • Should I be looking some more for cells with validation or not?



              Edit



              @DanielMcCracken has a valid point about changing the error chain



              • I updated the answer to preserve the previous error





              share|improve this answer



























                up vote
                0
                down vote













                I would suggest that HasValidation() returns either True or False, not maybe?...




                Option Explicit

                Public Function HasValidation(ByVal rng As Range) As Boolean
                Dim itHas As Boolean, eID As Long, eSRC As String, eDESC As String

                If Err.Number <> 0 Then
                eID = Err.Number
                eSRC = Err.Source
                eDESC = Err.Description
                Err.Clear
                End If

                On Error Resume Next
                If Not rng Is Nothing Then
                itHas = Not Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng) Is Nothing
                End If

                If Err.Number <> 0 Or eID <> 0 Then
                If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
                End If
                HasValidation = itHas
                End Function



                Or GetValidationRange() that returns a Range or Nothing




                Public Function GetValidationRange(ByVal rng As Range) As Range
                Dim vRng As Range, eID As Long, eSRC As String, eDESC As String

                If Err.Number <> 0 Then
                eID = Err.Number
                eSRC = Err.Source
                eDESC = Err.Description
                Err.Clear
                End If

                On Error Resume Next
                If Not rng Is Nothing Then
                Set vRng = Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng)
                End If

                If Err.Number <> 0 Or eID <> 0 Then
                If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
                End If
                Set GetValidationRange = vRng
                End Function



                .



                In your code



                • The parameter name (cell) implies that it expects a single cell

                • The Null return type can cause issues (not very used in normal operations)

                • As a user of the function I don't really know what to do with the result

                  • Should I be looking some more for cells with validation or not?



                Edit



                @DanielMcCracken has a valid point about changing the error chain



                • I updated the answer to preserve the previous error





                share|improve this answer

























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  I would suggest that HasValidation() returns either True or False, not maybe?...




                  Option Explicit

                  Public Function HasValidation(ByVal rng As Range) As Boolean
                  Dim itHas As Boolean, eID As Long, eSRC As String, eDESC As String

                  If Err.Number <> 0 Then
                  eID = Err.Number
                  eSRC = Err.Source
                  eDESC = Err.Description
                  Err.Clear
                  End If

                  On Error Resume Next
                  If Not rng Is Nothing Then
                  itHas = Not Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng) Is Nothing
                  End If

                  If Err.Number <> 0 Or eID <> 0 Then
                  If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
                  End If
                  HasValidation = itHas
                  End Function



                  Or GetValidationRange() that returns a Range or Nothing




                  Public Function GetValidationRange(ByVal rng As Range) As Range
                  Dim vRng As Range, eID As Long, eSRC As String, eDESC As String

                  If Err.Number <> 0 Then
                  eID = Err.Number
                  eSRC = Err.Source
                  eDESC = Err.Description
                  Err.Clear
                  End If

                  On Error Resume Next
                  If Not rng Is Nothing Then
                  Set vRng = Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng)
                  End If

                  If Err.Number <> 0 Or eID <> 0 Then
                  If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
                  End If
                  Set GetValidationRange = vRng
                  End Function



                  .



                  In your code



                  • The parameter name (cell) implies that it expects a single cell

                  • The Null return type can cause issues (not very used in normal operations)

                  • As a user of the function I don't really know what to do with the result

                    • Should I be looking some more for cells with validation or not?



                  Edit



                  @DanielMcCracken has a valid point about changing the error chain



                  • I updated the answer to preserve the previous error





                  share|improve this answer















                  I would suggest that HasValidation() returns either True or False, not maybe?...




                  Option Explicit

                  Public Function HasValidation(ByVal rng As Range) As Boolean
                  Dim itHas As Boolean, eID As Long, eSRC As String, eDESC As String

                  If Err.Number <> 0 Then
                  eID = Err.Number
                  eSRC = Err.Source
                  eDESC = Err.Description
                  Err.Clear
                  End If

                  On Error Resume Next
                  If Not rng Is Nothing Then
                  itHas = Not Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng) Is Nothing
                  End If

                  If Err.Number <> 0 Or eID <> 0 Then
                  If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
                  End If
                  HasValidation = itHas
                  End Function



                  Or GetValidationRange() that returns a Range or Nothing




                  Public Function GetValidationRange(ByVal rng As Range) As Range
                  Dim vRng As Range, eID As Long, eSRC As String, eDESC As String

                  If Err.Number <> 0 Then
                  eID = Err.Number
                  eSRC = Err.Source
                  eDESC = Err.Description
                  Err.Clear
                  End If

                  On Error Resume Next
                  If Not rng Is Nothing Then
                  Set vRng = Intersect(rng.SpecialCells(xlCellTypeAllValidation), rng)
                  End If

                  If Err.Number <> 0 Or eID <> 0 Then
                  If eID = 0 Then Err.Clear Else Err.Raise eID, eSRC, eDESC
                  End If
                  Set GetValidationRange = vRng
                  End Function



                  .



                  In your code



                  • The parameter name (cell) implies that it expects a single cell

                  • The Null return type can cause issues (not very used in normal operations)

                  • As a user of the function I don't really know what to do with the result

                    • Should I be looking some more for cells with validation or not?



                  Edit



                  @DanielMcCracken has a valid point about changing the error chain



                  • I updated the answer to preserve the previous error






                  share|improve this answer















                  share|improve this answer



                  share|improve this answer








                  edited Apr 19 at 1:11


























                  answered Apr 18 at 0:22









                  paul bica

                  1,059613




                  1,059613






















                       

                      draft saved


                      draft discarded


























                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192335%2fcheck-if-a-range-in-excel-contains-datavalidation%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Popular posts from this blog

                      Greedy Best First Search implementation in Rust

                      Function to Return a JSON Like Objects Using VBA Collections and Arrays

                      C++11 CLH Lock Implementation