当我指代一个未命名的范围

时间:2019-09-11 10:53:36

标签: excel vba worksheet-function worksheet

我试图将下拉菜单放在Excel工作表中,并将另一个工作表中的选项放在另一个工作簿中。我之所以使用VBA,是因为我想基于另一个下拉菜单来自定义这些选项。我设法通过在源工作表中命名范围来做到这一点,但是该文件是只读的,因此我无法保存名称来自动执行该过程。因此,我尝试仅在引用中使用列名(例如$ B:$ B,我只需要B列),但是当我运行宏时,它会因运行时错误1004而停止。

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim KeyCells As Range
    Set KeyCells = Range("H6")

    If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
        Call main
    End If
End Sub

Private Sub main()
    reason = Range("H6").Value
    List = ""

    If reason = "Project ID/Task ID" Then
        List = "=PIDTID"
    Else
        List = "=Cost_Center"
    End If

    With Range("I6").Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
            Operator:=xlBetween, Formula1:=List
        .IgnoreBlank = True
        .InCellDropdown = True
        .InputTitle = ""
        .ErrorTitle = ""
        .InputMessage = ""
        .ErrorMessage = ""
        .ShowInput = True
        .ShowError = True
    End With
End Sub

这是我的宏,如您所见,更改H6时会调用main(),因为这是我的其他下拉菜单所在的位置。然后,根据该单元格中的值,为List分配一个值,该值等于引用另一个工作表中范围的已定义名称。

作为示例,如果PIDTID名称等于='[20190812_WP_and_CostCenters_Responsible.xls]Projects responsibles'!WBSName,则脚本可以工作。请注意,WBSName是源表中列B的名称。

如果我将PIDTID设置为='[20190812_WP_and_CostCenters_Responsible.xls]Projects responsibles'!$B:$B,我将在第

行得到错误信息

.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _ Operator:=xlBetween, Formula1:=List

Cost_Center名称的作用相同。

我想提一下,这些测试是在打开源文件的情况下完成的。如果我尝试将其关闭,则会收到相同的错误。

是否有摆脱错误的方法,或者可以不用命名而引用其他工作簿表中的单元格的另一种方法?我也想无需打开源文件就可以工作。谢谢!

2 个答案:

答案 0 :(得分:1)

就像JvdV在评论中所写的那样,这是因为您不能在列表引用另一个工作簿的地方使用数据验证,至少不能以简单的方式。

external reference in Data Validation not possible

您可以通过使用此公式将命名范围添加到可写工作簿中来对其进行绕行(假设Cost_Center位于C列中)

=IF(Sheet1!H6="PIDTID",OFFSET('[20190812_WP_and_CostCenters_Responsible.xls]Projects responsibles'!$B:$B,0,0),OFFSET('[20190812_WP_and_CostCenters_Responsible.xls]Projects responsibles'!$C:$C,0,0))

,然后在数据验证/宏中使用此命名范围。 缺点是必须打开源工作簿才能使下拉菜单正常工作

答案 1 :(得分:1)

  

“是否有一种方法可以消除该错误,或​​者可以通过另一种方式引用其他工作簿中的单元格而无需命名它们?我也想无需打开源文件就可以工作谢谢!”

让我试试看:)

根据this文档,您不能对其他工作簿使用引用(没有命名范围)。而且当然不在封闭的工作簿中。有关此问题,请参考@ Gh3ttoKinG:)。

因此,这样做可能更聪明,但要不打开,我会想到使用ExecuteExcel4Macro的工作簿。在@SiddharthRout的this答案的帮助下,我们可以开始从已关闭的工作簿中提取信息:

Sub Test()

Dim wbPath As String, wbName As String
Dim wsName As String, cellRef As String
Dim Ret As String
Dim lr As Long
Dim arr() As String

wbPath = "C:\Users\....\SO\"
wbName = "SO.xlsx"
wsName = "Sheet1"

'Get the last row from B column, notice we need R1C1 notation for Excel4Macro
lr = ExecuteExcel4Macro("COUNTA('" & wbPath & "[" & wbName & "]" & wsName & "'!C2)")

'Let's use an array to fill our validation list with later on
ReDim arr(1 To lr)
For x = 1 To lr
    arr(x) = ExecuteExcel4Macro("'" & wbPath & "[" & wbName & "]" & wsName & "'!R" & x & "C2")
Next x

'Join the array together to make a string which will be accepted in the validation list
With Range("I6").Validation
    .Delete
    .Add Type:=xlValidateList, Formula1:=Join(arr, ",")
    .IgnoreBlank = True
    .InCellDropdown = True
    .InputTitle = ""
    .ErrorTitle = ""
    .InputMessage = ""
    .ErrorMessage = ""
    .ShowInput = True
    .ShowError = True
End With

End Sub

有些事情我会尝试进行“平滑处理”,例如COUNTA并不是获取lr变量的最佳选择,此外,还有一种方法可以将完整范围提取到{ {1}}变量。

但是,这可能会激发一些创意;)


编辑

检索字符串数据最后一行的另一种方法可能是使用arr(),如下所示:

MATCH