2016-02-25 70 views
0

UDF“NAV()”旨在根据第一个参数(始终为日期)在网络驱动器上查找正确的报告,然后遍历所有工作表以找到与第二个参数相同的行和第三个参数相同的一列(第二个和第三个可以是文本或数字)。Excel VBA UDF在即时窗口中执行,在工作表上失败

在即时窗口中可靠地工作。总是返回#VALUE!当在工作表上使用时,例如=资产净值(D7,D8,D9)或=资产净值(2/19/2016,“资产净值”,“221-I”)。

一般来说,如果试图改变UDF中的其他单元格,但看起来像是可以得到这种行为,但我的函数不这样做。此外,我相信所有范围参考指定哪个工作簿和工作表,所以我不认为这是问题。我不确定接下来要看的地方。

函数还会尝试通过Outlook向我发送一份报告,当它无法找到用户正在查找的内容时。我不知道这是否相关。

再一次,令人困惑的是,这段代码似乎在即时窗口中工作正常,但只给了#VALUE!当在工作表上使用时。

我在哪里可以查看下面的代码来确定导致NAV()在即时窗口中正常工作的原因,但总是产生#VALUE!在工作表上使用时?

Option Explicit 

Function NAV(ByVal NAVDate As Date, ByVal matchRow As Variant, ByVal matchColumn As Variant) As Variant 
'Application.ScreenUpdating = False 
Application.Volatile True 

    NAV = FindItemOnWorksheet(NAVDate, matchRow, matchColumn) 

'Application.ScreenUpdating = True 
End Function 


Function FindItemOnWorksheet(ByVal NAVDate As Date, ByVal ItemSpecies As Variant, ByVal ItemGenus As Variant) As Variant 
' Finds Item by opening NAV workbook with correct date, activating correct worksheet, and searching for correct row and column 
Dim startingRange As Range 
Dim ws As Worksheet 
Dim wb As Workbook 
Dim theDate As Date 
Dim theItemSpecies As String 
Dim theItemGenus As String 

theDate = NAVDate 
theItemSpecies = ItemSpecies 
theItemGenus = ItemGenus 

Set wb = GetWB(NAVDate) 

'Loop through ws 
Dim WS_Count As Integer 
Dim i As Integer 

WS_Count = wb.Worksheets.Count 

For i = 1 To WS_Count 


    Set ws = wb.Worksheets(i) 
    Set startingRange = ws.Range("A1:Z100") 

    Dim theRow As Range 
    Dim theColumn As Range 

    Set theRow = startingRange.Cells.Find(theItemSpecies, SearchDirection:=xlPrevious, lookat:=xlWhole) 
    If Not (theRow Is Nothing) Then 
     Set theColumn = startingRange.Cells.Find(theItemGenus, SearchDirection:=xlPrevious, lookat:=xlWhole) 
     If Not (theColumn Is Nothing) Then 
      FindItemOnWorksheet = ws.Cells(theRow.Row, theColumn.Column).Value 

      wb.Close 
      Exit Function 
     End If 
    End If 

Next i 
'Loop if no hit on either row or column Find() 

'following executes only if no match found 
MsgBox "No Match Found. Make sure you are entering arguments--" & vbNewLine & _ 
     "  The Date of NAV, " & vbNewLine & _ 
     "  the entry found in the right row of NAV workbooks (e.g. 'Net Asset Value'), " & vbNewLine & _ 
     "  the right column (e.g. 'Fund')." & vbNewLine & _ 
     " This function will only find exact matches." & vbNewLine & vbNewLine & _ 
     "Now emailing developer to ask for a fix." 

Dim OutApp As Object 
Dim OutMail As Object 
Dim strbody As String 

Set OutApp = CreateObject("Outlook.Application") 
Set OutMail = OutApp.CreateItem(0) 

strbody = "User attempted" & _ 
       "=FindItemOnWorksheet(" & theDate & ", " & theItemSpecies & ", " & theItemGenus & ")" & vbNewLine & _ 
       "theDate type " & TypeName(theDate) & vbNewLine & _ 
       "theItemSpecies type " & TypeName(theItemSpecies) & vbNewLine & _ 
       "theItemGenus type " & TypeName(theItemGenus) 

On Error Resume Next 
With OutMail 
    .To = <Address Removed> 
    .CC = "" 
    .BCC = "" 
    .Subject = "FindItemOnWorksheet Error" 
    .Body = strbody 
    '.Attachments.Add ("C:\file.xlsx") 
    .Send 
End With 
On Error GoTo 0 

Set OutMail = Nothing 
Set OutApp = Nothing 

FindItemOnWorksheet = "Error" 
'wb.Close 
Exit Function 
End Function 


Function GetWB(ByVal NAVDate As Date) As Workbook 
'Open requested workbook, return to parent procedure 

Dim wbPath As String 
Dim wbYear As String 
Dim wbMonth As String 

Dim wbWeek As String 

Dim wbFile As String 
Dim wbString As String 
Dim wb As Workbook 
Dim BackADay As Boolean 

Dim OriginalNAVDateRequested As Date 
OriginalNAVDateRequested = NAVDate 

BackADay = True 

'Loop through possible file tree structures and dates to find the closest NAV in the past to the date requested. 
Do While BackADay = True 

    'Don't go back to a previous week if cannot find current NAV 
    If OriginalNAVDateRequested - NAVDate > 4 Then 
     BackADay = False 
    End If 

    wbPath = <Network Path Removed> 
    wbYear = CStr(Year(NAVDate)) & "\" 
    wbMonth = MonthName(Month(NAVDate)) & " " & wbYear 

    wbWeek = DateFormat(NAVDate) & "\" 

    wbFile = Dir(wbPath & wbYear & wbMonth & wbWeek & "*Valuation Package*.xlsx") 

    'Pricings with distributions have differing tree structure 
    If wbFile = "" Then 
     wbWeek = wbWeek & "POST Distribution " & wbWeek 
     wbFile = Dir(wbPath & wbYear & wbMonth & wbWeek & "*Valuation Package*.xlsx") 
     If wbFile = "" Then 
      NAVDate = NAVDate - 1 
     Else: BackADay = False 
     End If 
    Else: BackADay = False 
    End If 

Loop 

wbString = wbPath & wbYear & wbMonth & wbWeek & wbFile 

Set wb = Workbooks.Open(wbString, UpdateLinks:=False, ReadOnly:=True) 
Set GetWB = wb 

End Function 

Function DateFormat(ByVal X As Date) As String 
'Appends leading zeroes if needed to achieve form "00" for any two digit integer, and converts to string 
Dim MM As String 
Dim DD As String 
Dim YYYY As String 

If Month(X) < 10 Then 
    MM = "0" & CStr(Month(X)) 
Else 
    MM = CStr(Month(X)) 
End If 

If Day(X) < 10 Then 
    DD = "0" & CStr(Day(X)) 
Else 
    DD = CStr(Day(X)) 
End If 

YYYY = CStr(Year(X)) 

DateFormat = MM & "." & DD & "." & YYYY 

End Function 
+0

您应该将所有输入参数定义为“Variant”。 – PatricK

+0

谢谢,PatricK。我将所有输入参数定义为“Variant”,然后尝试删除所有类型定义。两者都产生相同的行为。 –

+0

'NAV()'和'FindItemOnWorksheet()''Variant'输入类型?您将需要更改代码以转换输入数据。尝试通过它。我认为如果你在即时窗口这样做,你会得到同样的错误:'?NAV(Range(“D7”),Range(“D8”),Range(“D9”))' – PatricK

回答

0

您可以在Worksheet_Change事件中打开工作簿。

出于演示,如果Sheet1!A2的变化,Excel将尝试与该单元格的值打开工作簿的名称,然后输出状态Sheet1!A4

在一个模块下认沽:

Option Explicit 

Function TryOpenWB(ByVal oItem As Variant) As Variant 
    Dim sOut As String 
    Dim oWB As Workbook 
    On Error Resume Next 
    Set oWB = Workbooks.Open(CStr(oItem)) 
    If oWB Is Nothing Then 
     sOut = "Cannot open """ & CStr(oItem) & """" 
    Else 
     sOut = "Opened """ & CStr(oItem) & """ successfully." 
     'oWB.Close 
    End If 
    TryOpenWB = sOut 
End Function 

然后在下面的工作表模块(我用工作表Sheet1演示):

​​

所以这个想法是打开工作簿只有当某些单元格地址匹配。

+0

谢谢你与我粘在一起,PatricK。解决我的问题的真正关键只是工作表函数无法打开工作簿的信息,但工作表事件可以触发打开工作簿的例程。我的代码看起来和上面的很不一样。我可能会让它按钮驱动;修改后,我会在原始问题中更新。 –

相关问题