Reputation: 17
I'm currently using autofilter to filter on two columns. If the result of the autofilter is blank for only visible cells, it will add a new row. If any rows other than the header are found, it will instead show a MsgBox. The problem is that the row count is always returning 1. I've tried redefining "rng" a few ways to no avail.
Dim ws As Worksheet
Dim rng As Range
Set ws = Sheets("Scored Items")
Worksheets("Scored Items").Activate
ws.AutoFilterMode = False
With ws
.Range("A:D").AutoFilter Field:=1, Criteria1:=AssetBox.Text
.Range("A:D").AutoFilter Field:=4, Criteria1:=PartBox.Text
Set rng = .Range("A:A").SpecialCells(xlCellTypeVisible)
If (rng.Rows.Count = 1) Then
'Add new row based on VBA form
Else
MsgBox "Item has already been scored"
End If
End With
ws.Cells.AutoFilter
Upvotes: 0
Views: 2118
Reputation: 53623
If the range object is non-contiguous, than .Rows.Count
will only return the number of rows in the first Area
of the range, which in this case will be the "header" row. (NB: If your filter was such that the first row of data was visible, but the second was not, you'd get 2
as the result).
When working with filtered ranges, you need to iterate the Areas
in the range.
Dim aRange as Range
For Each aRange in rng.Areas
If (aRange.Rows.Count = 1) Then
'Add new row based on VBA form
Else
MsgBox "Item has already been scored"
End If
Next
In this case, you probably want to flag some error if Areas.Count > 2
and also if any of the aRange.Rows.Count <> 1
etc.
If you're using AutoFilter
merely to check for the existence of a value in this range (i.e., to prevent duplicate entries in a table?), that's a rather clunky way to do it and you would probably be better served using the COUNTIF
function.
If Application.WorksheetFunction.CountIf(.Range("A:A"),AssetBox.Text) = 1 And _
Application.WorksheetFunction.CountIf(.Range("D:D"), PartBox.Text) = 1 Then
'Add new row based on VBA Form
Else
MsgBox "Item has already been scored"
End If
Follow-up from your comment, since this is a UI, I would use both. Obviously, you want the AutoFilter to display the data to the user, so keep that. But rather than trying to hack around the various Areas
of the filtered data, just use the COUNTIF
function to check
'Filter data to display to the user
Dim dataRange As Range
Set dataRange = ws.Range("A:D")
With dataRange
.AutoFilter Field:=1, Criteria1:=AssetBox.Text
.AutoFilter Field:=4, Criteria1:=PartBox.Text
'Check if part already been scored
With Application.WorksheetFunction
If .CountIf(.Columns(1), AssetBox.Text) = 1 And _
.CountIf(.Columns(4), PartBox.Text) = 1 Then
'Add new row based on VBA Form
Else
MsgBox "Item has already been scored"
End If
End With
'unfilter the data
ws.Cells.AutoFilter
Upvotes: 4
Reputation: 9976
Instead of checking the Rows.Count, check Cells.Count for visible rows. Try it like this...
Dim ws As Worksheet
Dim rng As Range
Dim lr As Long
Set ws = Sheets("Scored Items")
lr = ws.UsedRange.Rows.Count
Worksheets("Scored Items").Activate
ws.AutoFilterMode = False
With ws
.Range("A1:D" & lr).AutoFilter Field:=1, Criteria1:=AssetBox.Text
.Range("A1:D" & lr).AutoFilter Field:=4, Criteria1:=PartBox.Text
Set rng = .Range("A1:A" & lr).SpecialCells(xlCellTypeVisible)
If rng.Cells.Count = 1 Then
'Add new row based on VBA form
Else
MsgBox "Item has already been scored"
End If
End With
ws.AutoFilterMode = False
Upvotes: 3