Northwind 2.0 您應該了解的事項

套用到
Microsoft 365 Access Access 2021 Access 2019

此處的內容可能適用於 Northwind 2.0 開發人員版和入門版。 

Access VBA 參考

VBA (Visual Basic for Applications) 是所有 Office 產品中使用的程式設計語言。 學習 VBA 可讓您使用所有的 Office 產品, (不只是 Access) 。
搜尋「操作方法」時,請務必尋找 Access 的特定範例,並在搜尋中包含 Microsoft Access。 通常其他 Office 產品的解決方案可行,但無法保證。 Microsoft Access 是成熟的產品;這意味著那裡有很多例子;這對您來說很棒! 

這也表示您仍然可以查看有關 Access 程式設計的舊書籍。 許多舊書仍然可以在二手書網站上以原始成本的一小部分購買。 請查看 Microsoft 網站以確定仍支援哪些版本的 Access,並選擇與那些版本一起使用。

Office 終止支援資源 - 部署 Office |Microsoft Learn

以下是一些 Microsoft Access 文件的連結。

信任的位置和啟用的內容

Microsoft Access 檔案是 Office 檔案。 Office 檔案必須位於「信任的位置」,或是「啟用其內容」。 這些項目會因為您所建立,或是來自可信任的來源而被視為「安全」。 每次開啟任何 Office 檔案時,都會發生檢查信任的位置。 從現在開始,我們將此稱為「受信任/啟用」。 注意:如果從不受信任的位置發行並開啟新版本的應用程式,則會重複啟用內容的程序。

深入了解信任的位置。:

巨集、函數和子

巨集、函式和子是您在 Access 資料庫中實作商務邏輯的方式。 開始之前,請務必先了解 範圍和可見度

事件 (例如按一下控制項) 表單上的控制項 (例如按鈕、文字方塊、標籤等 ) 會觸發其他程序,例如新增、刪除記錄或開啟表單。 您可以使用巨集或 VBA 來實作這些程序。 Northwind Starter Edition 主要使用巨集,也有一些 VBA 在其中巨集無法執行必要的功能。 Northwind Developer Edition 主要使用 VBA。 

某些控制項類型具有內建精靈,可自動建立巨集。 例如,新增命令按鈕至表單會開啟精靈,提供數個按鈕功能選項。 新增下拉式方塊會開啟精靈,並將其設定為在表單上尋找特定記錄。 

「瀏覽窗格」是您檢視及存取所有資料庫物件的主要方式,預設會顯示在 Access 視窗的左側。 
Northwind 瀏覽窗格已自訂。 我們建立了名為 Northwind Starter 2.0 的自訂類別。 這使我們能夠按功能區域組織對象。

VBA 中變數的範圍和可見度

了解 Access/Office 內的 範圍和可見度 非常重要。 您可以從這裡開始:

持續變數

有時候,您需要在建立變數的物件超出範圍之後存在變數。 請參閱上方的 範圍和可見度 。 有三種主要方法可以做到這一點:公共變數、TempVars 和將值儲存在本機表中。 許多開發人員混合使用這些。 每個都有其優點和缺點。  在這裡深入了解每個內容:

VBA 模組公開變數:

TempVars:

將值儲存在本機資料表中

  • 目前工作階段存在公用變數和 TempVar,並在應用程式關閉時超出範圍。 但是,如果您想要在工作階段之間保留使用者特定變數呢? 您可以將這些類型的值儲存在本機資料表中。 在 Northwind 2.0 中,會將其中一個變數儲存在稱為 SystemSettings 的資料表中。 資料表中的值為 ShowWelcome。 這個值會告訴 Access 您是否要在每次登入時看到歡迎畫面。

OpenArgs 和 StringFormat ()

開發人員經常需要將參數從一個表單傳遞到另一個表單,或從表單傳遞到報表。 這些參數傳達重要訊息,然後被呼叫的函數將使用這些資訊來配置自身。 第二種表單或報表可透過數種方式從第一種表單取得資訊。 以下是其中幾種方法:

  1. 第二種形式可以「回顧」第一種形式來獲取一些值,可能是在可見或不可見的控制下。  例如:
    lngCustomerID = Forms!FirstForm!cboCustomerID 
  2. 第一種形式可以將值儲存為全域變數或 TempVars。 例如:
    g_lngUserID = Me.cboUserID 
    TempVars.Add “UserID”, Me.cboUserID

Northwind Developer Edition 以及我們的專業領域中經常使用的方法是使用 DoCmd.OpenForm 或 OpenReport 的 OpenArgs 引數。 例如:

DoCmd.OpenForm "frmCompanyDetail", OpenArgs:=StringFormat("CompanyID={0} &CompanyTypeID={1}", Me.VendorID, ctVendor)

我們在這裡結合兩種技術: (1) 使用 OpenArgs 傳入 VendorID 和 VendorType,以及 (2) 使用 StringFormat () 函式來建立,例如,此字串:

CompanyID=5&CompanyTypeID=2 

這個字串看起來非常像瀏覽器中使用的查詢字串。 它包含一或多個以符號字元分隔的「名稱/值組」:

name1=value1&name2=value2

這類字串的優點是每個值都有其名稱。 將此與更簡單的方法相比,您只會將 OpenArgs 設定為 “5,2”。  在這種情況下,需要努力找出每個值的含義。 命名每個值可讓查詢字串「自描述」,這是很好的程式設計做法。

DoCmd.OpenForm 的接收端,我們通常處於 Form_OpenForm_Load 事件中,並且想要將 OpenArgs 字串剖析成其元件。

在 Northwind 中,您可以使用 StringToDictionary 函數來執行這項工作。 它採用類似查詢字串的函數,並將其剖析成其元件。 這些元件接著會儲存在 Scripting.Dictionary 物件中。 請注意,要執行這項操作,您需要使用 工具 > 參考, 並設定指令 碼執行階段 (scrrun.dll) Microsoft 參考。

Dictionary 物件的功能和優點包括:

  • 元素的順序並不重要
  • 新增和移除集合元素的簡單函數
  • 迴圈集合的函數,讓您知道其中的內容
  • Exists 函數,可讓您測試特定元素是否可用

字典物件的使用出現在整個 Northwind。 例如,frmGenericDialog 中的Form_Load事件。

錯誤處理

在 Access 中使用控制精靈建立的巨集,很少會包含錯誤處理;使用控制精靈建立的 VBA 可能僅限為一般 MsgBox Err.Description

在 Northwind 2.0 中,我們會示範如何在使用 VBA 程式碼時更有效地執行。 我們實作了所謂的 全域錯誤處理常式。 在任何程序中發生的錯誤都會在全域層級呼叫函數來顯示錯誤。 這裡的最大優點是錯誤處理是一致的。 如果消息需要更改 (,例如,額外顯示錯誤編號或將錯誤記錄到文件) ,則只需在一個地方完成。 

clsErrorHandler 是實作錯誤處理程式碼的類別模組。 類別模組將其所有主函數和輔助函數保存在一個單元中,從而封裝程式碼。

AutoExec 巨集會呼叫 modStartup 中的 Startup 函數。 在 Starter Edition 中,函數會建立 clsErrorHandler 的執行個體,並將它儲存為可在整個應用程式中使用的全域變數。 在 Dev 版本中使用靜態類別 – 請參閱類別模組頂部的註解。

事實上,程序中的錯誤處理程式碼非常一致,以至於我們能夠使用特定的 VBA 程式碼在不到五分鐘的時間內建立所有程式碼,該程式碼為每個程序配備適當的錯誤處理常式。 (範本) 中未包含代碼。 Northwind 2.0 Starter 和 Developer 範本版本最初都配備了這種錯誤處理方法。 
'

改善錯誤處理

從 Northwind 開發人員版 2.2 版開始,感謝 Access 社群的意見反應,錯誤處理常式已得到改善。 入門版保持不變。 

基本上,2023 年 4 月發行的舊版 (2.0) 中的錯誤處理常式為:

Public Sub HandleError(…)
    MsgBox Err.Description
End Sub

在 2.2 版中,它已升級為:

Public Sub HandleError (…, Optional ByVal IsEventProcedure As Boolean = False)
    If Not IsEventProcedure Then
        Err.Raise lngError, strErrSource
    End If
    MsgBox Err.Description
End Sub

為了了解為什麼要進行此更改,讓我們先了解是什麼讓程式碼運行:

  • AutoExec 巨集會呼叫啟動程序,其會在開啟第一個表單之前執行一些初始化。
  • 使用者與應用程式互動,例如開啟表單或按一下按鈕,導致事件程序觸發,例如 Form_LoadcmdPrintInvoice_Click
    '

除了事件程序之外,應用程式還有子常式和函數(主要在模組中),並且該代碼是從事件程序呼叫的。 這些稱為「標準」程序。

在 Northwind 2.0 版中,標準程序會處理自己的訊息錯誤,但不會以某種方式通知呼叫事件程序發生錯誤。 如果事件程序具有後續程式碼,且無論呼叫程序處理的先前錯誤為何,都應執行,則此情況可能會很糟糕。 當然,我們可以用返回成功或失敗的函數替換子程式,並相應地對事件過程進行編碼,但這並不總是一個選項。

在 Northwind 2.2 版中,標準程序不會處理錯誤訊息,而是使用 Err.Raise,將它們回報回呼叫事件程序。 然後,呼叫事件程序會顯示引發的錯誤,並在 Exit_Handler繼續。 這樣比較好,因為它可讓呼叫程序正常結束。

若要使用 Northwind 2.2 版程式碼,事件程序必須將第三個引數傳遞到 HandleError ,指出呼叫端是事件程序。 Northwind Dev Edition 已更新為執行此操作。

一個更強大的錯誤處理程序模組將支持“堆棧” (陣列) 上的“推送和彈出”過程。 第一個元素一律是事件程序,因此不需要額外的引數。 這個實作超出了 Northwind Dev Edition 的目標。

MRU 清單

MRU[最近使用 ] 是最近使用的訂單和訂購單清單。 您可能會想要經常返回這些頁面,將它們置於下一個狀態。 MRU 清單通常顯示在 Office 產品中,是最近使用過的檔案清單,您可能會想要再次重新開啟。

在 Northwind Dev 版本中,若要實作 Starter 版本中尚不存在的 MRU 功能 () 您必須先建立下列項目:

  1. 儲存 MRU 資訊的資料表。
  2. 開啟訂單或訂購單 (PO) 時更新資料表的代碼。
  3. 更新功能區中 MRU 下拉式清單的代碼。
  4. 從功能區選取 MRU 項目時載入項目的代碼。

讓我們更詳細地看看這些。 

1. 儲存 MRU 資訊的表格。

表MRU的設計值得回顧,尤其是它的指標。 請注意,有一個重複索引 SortIdx 可協助快速排序功能區下拉式清單中的 MRU 項目,還有一個唯一索引可強制執行商務規則,即每個使用者只能對每個使用者執行一個項目只能出現一次。 例如,開啟相同的訂單兩次不會在 MRU 資料表中建立兩筆記錄。

此資料表利用了資料庫中所有 MRU 相關 PK (主索引鍵) 欄位都是 [自動編號] 的優勢,因此長整數資料類型可用於 PKValue

2. 開啟訂單或 P.O. 時更新表格的代碼。

在 NW2 中,我們選擇只在建立新記錄時新增到 MRU 清單,而不是在再次更新現有記錄時新增到 MRU 清單。 我們當然可以將 AddToMRU 呼叫從 Form_AfterInsert 轉移到 Form_AfterUpdate 來支持這一點。

AddToMRUDeleteFromMRU 程序是在 modGlobal 中實現的,這是一個 Standard 模塊,其公共程序可以從任何形式中看到。

AddToMRU (顧名思義) 將新項目新增至 MRU 表格,然後選擇性地將其修剪,如果最舊的記錄已增長到大小上限 (MAX_MRU_COUNT) ,則刪除該記錄。 最後一個步驟可能是 Access 開發人員最不為人所知的步驟:必須重新整理功能區下拉式清單,這是透過呼叫 InvalidateControl 來完成的。 這是向功能區發出的訊號,要求重新執行其初始化程序。 

3. 更新功能區中 MRU 下拉式清單的代碼。

在啟動時和呼叫 InvalidateControl 之後,會執行一組複雜的函數以填入功能區。  這些程序由表格 uSysRibbons 中的功能區 XML 呼叫,其中部分表示:


<group id="gCurrentStatus" label="MRU">
    <box id="bxMRU" boxStyle="vertical">
        <dropDown id="ddMRU"
                  getItemCount="ddMRU_GetItemCount"
                  getItemLabel="ddMRU_GetItemLabel"
                  getSelectedItemIndex="ddMRU_GetSelectedItemIndex"
                  getItemID="ddMRU_GetItemID"
                  onAction="ddMRU_OnAction"
                  screentip="Most Recently Used Objects">
        </dropDown>
    </box>
</group>

這四個回呼函式會填入下拉式清單。 請注意,這與 此處 描述的標準下拉式方塊的想法非常相似。

如果您取消註解 modRibbonCallback 中的 Debug.Print 行並重新啟動應用程式,[立即視窗] 會呈現如下的順序:


ddMRU_GetItemCount    ddMRU    6 
ddMRU_GetItemLabel    ddMRU    0      Order 60, Proseware, Inc.
ddMRU_GetItemID       ddMRU    0       2 
ddMRU_GetItemLabel    ddMRU    1      Order 62, Best For You Organics Company
ddMRU_GetItemID       ddMRU    1       4 
ddMRU_GetItemLabel    ddMRU    2      Order 63, Wide World Importers
ddMRU_GetItemID       ddMRU    2       5 
ddMRU_GetItemLabel    ddMRU    3      Order 66, Proseware, Inc.
ddMRU_GetItemID       ddMRU    3       8 
ddMRU_GetItemLabel    ddMRU    4      Order 67, Best For You Organics Company
ddMRU_GetItemID       ddMRU    4       9 
ddMRU_GetItemLabel    ddMRU    5      Order 68, Adatum Corporation
ddMRU_GetItemID       ddMRU    5       10 
ddMRU_GetSelectedItemIndex  ddMRU    0

我們可以看到,Access 會先呼叫程序,傳回要在 ddMRU_GetItemCount 的 ByRef 引數中載入的項目數目。 這也是我們在 MRU 表上開啟查詢並快取它的時候,因為它即將被使用多次。 

然後,功能區會重複呼叫兩個程序來取得兩欄下拉式清單的識別碼和標籤值。 

最後,它會呼叫程序來取代應選取的項目。 (在我們的例子中,它是第一個 ) 。

4. 從功能區中選取 MRU 項目時載入項目的代碼。

就像任何其他功能區項目一樣,功能區 XML 中的 OnAction 屬性會指定要用來執行動作的回呼函數:


onAction="ddMRU_OnAction"

此程序是在 modRibbonCallback 中實作。 它會重複使用已開啟的資料錄集來尋找含有所選項目的記錄,然後根據所需的 TableName 開啟對應的表單,並傳入要載入的 PK 值。

深入了解