背景:
自最近以来,我开始了解通过使用AutoFilter
创建的秘密命名范围。通常(如果不是总是这样)将其称为“ _FilterDatabase”。
本来我想过玩一点,但后来卡在了它所指的Range
对象上。让我用以下示例进行解释:
测试数据:
| Header1 | Header2 |
|---------|---------|
| 50 | |
| 10 | |
| 30 | |
| 40 | |
| 20 | |
测试代码:
Sub Test()
With Sheet1
.Range("A1:B1").AutoFilter 1, ">40"
Dim rng As Range: Set rng = .Range("_FilterDatabase")
If rng.SpecialCells(12).Count > 2 Then
rng.Columns(2).Offset(1).Resize(rng.Rows.Count - 1, 1).Value = "Check"
End If
.Range("A1:B1").AutoFilter
End With
End Sub
没有结果
问题:
如果我在上面运行宏,将不会有结果。
问题:
使用.ShowAllData
方法而不是.AutoFilter
并运行两次代码可以解决此问题:
Sub Test()
With Sheet1
.Range("A1:B1").AutoFilter 1, ">30"
Dim rng As Range: Set rng = .Range("_FilterDatabase")
If rng.SpecialCells(12).Count > 2 Then
rng.Columns(2).Offset(1).Resize(rng.Rows.Count - 1, 1).Value = "Check"
End If
.ShowAllData
End With
End Sub
但是,.AutoFilter
清除了过滤器并将其从我们的范围中删除。在这两种情况下,秘密的命名范围都将保留在名称管理器下的Formulas
标签中。
有人知道为什么ShowAllData
会在第二轮运行中影响返回的命名范围吗?
答案 0 :(得分:2)
我已经找到了我自己的问题的答案(事后看来,这似乎不符合我的发现,因此我对其进行了编辑)。
根据我的问题,AutoFilter
将立即在水下创建一个加密的命名范围,通常(如果不是始终如此)称为"_FilterDatabase"
。我注意到的是以下内容:
.Range("A1:B1").AutoFilter 1, ">40" '-> Named range will refer to A1:B1
但是:
.Range("A1:B1").AutoFilter '-> Named range will refer to A1:B1
.Range("A1:B1").AutoFilter 1, ">40" '-> Named range will refer to A1:B6
这可以解释为什么我的代码末尾的AutoFilter
使得第二次也不能正常工作。但是,由于ShowAllData
不会不删除实际的过滤器(仅是标准),因此它将在第二次运行中识别出范围A1:B6
。因此,我需要做的是首先设置.AutoFilter
,以使命名范围选取正确的范围。现在,以下内容可以正常工作:
Sub Test()
With Sheet1
.Range("A1:B1").AutoFilter
.Range("A1:B1").AutoFilter 1, ">40"
Dim rng As Range: Set rng = .Range("_FilterDatabase")
If rng.SpecialCells(12).Count > rng.Rows(1).Cells.Count Then
rng.Columns(2).Offset(1).Resize(rng.Rows.Count - 1, 1).Value = "Check"
End If
.Range("A1:B1").AutoFilter
End With
End Sub
在逻辑上行不通的是什么呢?
.Range("A1:B1").AutoFilter '-> Named range will refer to A1:B1
Set rng = Set rng = .Range("_FilterDatabase")
rng.AutoFilter 1, ">40" '-> rng still refers to A1:B1
恢复:
AutoFilter
立即在AutoFilter
方法上创建一个秘密的命名范围。您不能直接使用条件初始化过滤器。这样做会混淆命名范围,并且现在只会引用第一行。必须按顺序使用它们!
有趣的部分是,这现在将不需要事先知道最后一个使用的行来创建范围对象的方法(但是,由于数据中的空白将使命名范围无效,因此可能仍然更喜欢该方法)。
答案 1 :(得分:1)
此过滤器无需使用AutoFilter.Range
即可正确过滤:
Sub test2()
Dim var As Range
Dim i As Long
With Sheets("Sheet1").Range("A1:C1")
.Range("B2:B6").Clear
.AutoFilter
.AutoFilter 1, ">50"
Set var = Sheet1.AutoFilter.Range
Set var = Intersect(var.SpecialCells(12), var.Offset(1, 0))
If Not (var Is Nothing) Then
For i = 1 To var.Areas.Count
var.Areas(i).Offset(0, 1).Resize(var.Areas(i).Rows.Count, 1).Value = "Check"
Next i
End If
.AutoFilter
End With
End Sub