2017-05-15 20 views
1

編輯爲清楚起見,現在該解決方案已被確定UDF參照命名錶錯誤時,另一個工作簿是活動

我是一個新手VBA建立一個UDF。該UDF涉及多個引用Excel表格上其他工作表工作簿VLOOKUP功能,如:

Twirecol = Application.WorksheetFunction.VLookup(i, Range("iterationtable"), 2, False) 

麻煩的是,如果另一工作簿是活動的,當Excel重新計算公式返回#VALUE錯誤。

我看到很多關於如何引用VBA和UDF中的其他工作簿和工作表的解決方案,但我不知道如何適當地限制這些表對象,以便他們保持專注於UDF所在的工作簿。請注意,我正在尋找一個解決方案,不會取決於工作表名稱或工作簿文件名或路徑,因爲所有這些可能隨時間而改變。

這是我對這個工作簿的名稱經理:Names Manager

這裏是整個UDF代碼:

Public Function voltagedrop(trenchlength As Integer, intlength As Integer) As String 
Application.Volatile 

Dim TLX As Integer 
Dim ILX As Integer 
Dim TVD As Single 
Dim IVD As Single 
Dim VD As Single 
Dim Twirecol As Integer 
Dim Iwirecol As Integer 
Dim i As Integer 


' Extended length variables account for extra length at end of strings 
TLX = trenchlength + 10 
ILX = intlength + 10 

i = 0 

Do 
i = i + 1 
    Twirecol = Application.WorksheetFunction.VLookup(i, Range("iterationtable"), 2, False) 
    Iwirecol = Application.WorksheetFunction.VLookup(i, Range("iterationtable"), 3, False) 

    ' Calculate voltage drops 
    TVD = Application.WorksheetFunction.VLookup(TLX, Range("trenchtable"), Twirecol, False) 
    IVD = Application.WorksheetFunction.VLookup(ILX, Range("inttable"), Iwirecol, False) 
    VD = TVD + IVD 

Loop Until VD < 0.025 

VD = 100 * Round(VD, 4) 
voltagedrop = Application.WorksheetFunction.VLookup(i, Range("iterationtable"), 4, False) & ": " & VD & "%"  

End Function 

解決方案(感謝@DavidZemens)

(*大衛的完整的答案是下面,這是我的總結)

如果這一直是一個傳統命名的區域,而不是一個表,我可以叫的範圍內,像這樣:

Twirecol = Application.WorksheetFunction.VLookup(i, ThisWorkbook.Names("iterationtable").RefersToRange, 2, False) 

但是,由於錶行爲不同於指定範圍(儘管同樣顯示在名稱管理器上) ,我需要調用這樣的範圍內:

Twirecol = Application.WorksheetFunction.VLookup(i, ThisWorkbook.Worksheets("Background Tables").ListObjects("iterationtable").Range, 2, False) 

然而,我的理想解決方案,避免了命名錶可言,如果在今後的工作表名稱的變化,因此它被證實了,我可以用牀單CodeName相反(在我的情況下爲sheet1):

Twirecol = Application.WorksheetFunction.VLookup(i, Sheet1.ListObjects("iterationtable").Range, 2, False) 

我在爲簡單起見,此示例代碼直接認定的範圍內,但每大衛的建議,我最終的代碼沒有使用一組變量的範圍。

+0

有什麼功能的其餘部分之前正確的工作簿?雖然是的,但你最後的猜測是正確的。您應該在範圍之前添加工作表(和/或工作簿,如果您有多個打開的),例如'... Vlookup(i,工作表(「Sheet1」)。範圍(「迭代表」),...' – BruceWayne

+0

Thanks @ BruceWayne編輯原始文章以包含整個代碼當工作簿處於活動狀態時工作良好... thisworkbook.range(「iterationtable」)不起作用......而是它給了我一個「編譯錯誤:方法或數據成員沒有找到「 –

+0

另外,關於工作表名稱,我試圖保持這個函數儘可能通用,以便由不太熟悉VBA的同事做出的未來修改不會意外地破壞它,包括避免引用表單是否有理由識別工作表,考慮到範圍的命名? –

回答

1

I am hoping there is an elegant solution such as...

thisworkbook.range("iterationtable") 

Although this does not work.

Range不是Workbook類的屬性,它是Worksheet類的屬性。

然而,命名區域是通過Names收集訪問。如果Name的作用域是工作簿(我認爲這是默認的),你應該能夠通過ThisWorkbook.Names("iterationtable").RefersToRange訪問它。

如果Name被限定在特定的工作表中,那麼您將需要執行ThisWorkbook.__WORKSHEET__.Names("iterationtable")...而不是__WORKSHEET__是包含工作表。


上面寫的假設,這是一個Name對象,但在馬特的截圖審查,很明顯,這實際上不是一個Name,而是ListObject(表):

enter image description here

雖然這些出現在名稱管理器,是一個名爲範圍類似的訪問,即,:

MsgBox ActiveSheet.Range("table1").Address ' etc... 

他們不是Names集合的成員(他們實際上是在ListObjects集合的一部分)等試圖呼籲他們像下面將引發1004錯誤:

MsgBox ActiveSheet.Names("table1").Address 

要解決此問題,則需要完全限定Range對象,即:

ThisWorkbook.Worksheets("Background Tables").Range("iterationtable") 

或者:

ThisWorkbook.Worksheets("Background Tables").ListObjects("iterationtable").Range 

之所以Range("iterationtable")有時工作(即,當它的ActiveSheet是證據充分的和正常,預期不適當作用域標識符的功能:Range總是到任何片材是在運行時主動,除非明確作用域否則。

This是如何避免臭名昭著的1004錯誤了良好的引物,但它歸結爲以上:適當範圍的對象,最好使用變量來代表他們。

Dim wsTables as Worksheet 
Dim iterTable As Range 
Dim trenchTable as Range 
Dim intTable as Range 

Set wsTables = ThisWorkbook.Worksheets("Background Tables") 'Declare the worksheet 
With wsTables 
    'Assigns each table's Range to a Range object variable: 
    Set iterTable = .ListObjects("iterationtable").Range 
    Set trenchTable = .ListObjects("Trench Table").Range 
    Set intTable = .ListObjects("Int Table").Range 
End With 

With Application.WorksheetFunction 
    Do 
     i = i + 1 
     Twirecol = .VLookup(i, iterTable, 2, False) 
     Iwirecol = .VLookup(i, iterTable, 3, False) 
     ' Calculate voltage drops 
     TVD = .VLookup(TLX, trenchTable, Twirecol, False) 
     IVD = .VLookup(ILX, iterTable, Iwirecol, False) 
     VD = TVD + IVD 
    Loop Until VD < 0.025 

    VD = 100 * Round(VD, 4) 
    voltagedrop = .VLookup(i, iterTable, 4, False) & ": " & VD & "%" 
End With 

最後:

including avoiding references to the sheet on which the named ranges are located.

確定,因此,如果用戶從「背景表」到別的改變工作表名稱,上面的代碼仍然會失敗。有一些方法來防止這種情況,如鎖定片進行編輯,和/或隱藏的工作表(假設用戶並不還需要輸入數據到片材等),或通過參考工作表其CodeName而不是其Name。這利用了這個事實,即when referred to by CodeName, the Worksheet is always implicitly a part of ThisWorkbook。要查找表的CodeName,它在括號中的項目窗格:

enter image description here

在上述方案中,你會改變這一行:

Set wsTables = ThisWorkbook.Worksheets("Background Tables") 'Declare the worksheet 

要:

Set wsTables = Sheet2 '<~~ The CodeName goes here, modify as needed! 

雖然工作表的CodeName是可讀/寫的(意思是精明的用戶可能是 c將它吊起來,他們需要通過VBA或手動通過VBE來完成,所以這在大多數情況下似乎不太可能)。

+0

謝謝大衛,這正是我正在尋找的。但是,我正在努力實施它。當我用'thisworkbook.names(「iterationtable」)替換我的'range(「iterationtable」)'。RefersToRange'時,我得到一個VALUE錯誤。我試着做一個測試宏,看看問題是否在其他地方:'Dim range1 as range' //'set range1 = thisworkbook.names(「iterationtable」)。ReferstoRange' //'msgbox range1'但是這也失敗了。我想我可以忽略一些愚蠢的東西? –

+0

請更新您的問題o包括您嘗試的故障排除。在評論中閱讀代碼很困難,而且當您將評論放入評論中時,唯一可能看到更多細節的人就是我,這限制了(顯着)可能會幫助您的人數。 –

+0

如果這在測試過程中失敗了,那麼似乎這個範圍在'ThisWorkbook'對象中不存在。 –

0

您是否嘗試通過使用工作簿名稱和工作表來完成對工作簿的所有調用?僅使用「範圍(」無論「)」將導致程序查看當前活動的任何工作簿的活動工作表。

嘗試改變調用格式爲:

Twirecol = Application.WorksheetFunction.VLookup(i, CorrectWorkbookName.CorrectWorksheetName.Range("iterationtable"), 2, False) 

當你與命名範圍,變「CorrectWorksheetName」改變「CorrectWorkbookName」這本書的名字到工作表的名稱包含命名範圍。

+0

只有當命名範圍在工作表範圍內時纔是如此。如果命名範圍在工作簿範圍內,則不應命名該工作表。 –

0

或許激活手

Set wb = ThisWorkbook 
wb.Activate 
TVD = Application.WorksheetFunction.VLookup(TLX, Range("trenchtable"), Twirecol, False) 
+0

感謝John,命名範圍的作用域爲工作簿,並且我試圖避免在UDF中命名工作簿或工作表,以防將來的名稱更改。目標是在工作簿不活動時保持UDF正常工作 - 換句話說,當我在另一個監視器上打開另一個文檔並重新計算某些內容時,我需要此UDF不會重新計算VALUE錯誤。 –

+0

https://social.msdn.microsoft.com/Forums/office/en-US/1c96dd88-84f3-415e-b531-8ea2d39d093a/udfs-that-work-in-all-open-workbooks?forum=exceldev –

相關問題