Northwind 2.0 Неща, които трябва да знаете

Отнася се за
Access за Microsoft 365 Access 2021 Access 2019

Съдържанието тук може да се отнася за Northwind 2.0 Developer Edition и Starter Edition. 

Справочни материали за Access VBA

VBA (Visual Basic for Applications) е езикът за програмиране, използван във всички продукти на Office. Изучаването на VBA ви позволява да работите с всички продукти на Office (не само с Access).
Когато търсите "как да", непременно потърсете конкретни примери за Access и включете Microsoft Access в търсенето. Често решенията за другите продукти на Office ще работят, но това няма гаранция. Microsoft Access е продукт за възрастни; Това означава, че има много примери; което е чудесно за вас! 

Това означава също, че по-старите книги за програмиране за Access са все още жизнеспособни за разглеждане. Много от по-старите книги все още са достъпни в сайтовете за употребявани книги на малка част от първоначалната им цена. Проверете в уеб сайта на Microsoft, за да установите кои версии на Access все още се поддържат, и продължете с тях.

Край на поддръжката за Office – разполагане на Office | Microsoft Learn

По-долу има някои връзки към документацията на Access в Microsoft.

Надеждни местоположения и разрешено съдържание

Файловете на 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:

Съхраняване на стойностите в локална таблица

  • Публичните променливи и TempVars съществуват за текущата сесия и излизат извън обхвата, когато приложението се затвори. Какво обаче става, ако искате да запазите специфичните за потребителя променливи в сесиите? Можете да съхранявате тези типове стойности в локална таблица. В 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, както и в професионалния ни живот, е използването на аргумента OpenArgs на DoCmd.OpenForm или OpenReport. Например:

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_Open или Form_Load и искаме да анализираме низа OpenArgs в неговите компоненти.

В Northwind можете да направите това с функцията StringToDictionary . Тя взема функция, подобна на на заявкаstring, и я анализира в нейните компоненти. След това тези компоненти се съхраняват в обекта Scripting.Dictionary . Обърнете внимание, че за целта трябва да използвате препратки към инструменти > и да зададете препратка към Microsoft Scripting Runtime (scrrun.dll).

Характеристиките и предимствата на обекта "Речник" са следните:

  • Редът на елементите не е важен
  • Прости функции за добавяне и премахване на елементи от колекцията
  • Функции за циклично обхождане на колекцията, така че да знаете какво има в нея
  • Функция Exists , за да можете да тествате дали определен елемент е наличен

Използването на обекта речник се вижда навсякъде в Northwind. Например събитието Form_Load във frmGenericDialog.

Коригиране на грешки

Макросите, създадени със съветниците за контроли в Access, рядко включват обработване на грешки; VBA, създаден със съветници за контроли, може да е ограничен до общ MsgBox Err.Description.

В Northwind 2.0 ви показваме как да го направите по-добре, когато използвате код на VBA. Вънедрихме така наречения манипулатор на глобални грешки. Грешките, които се случват в процедура, извикват функция на глобално ниво, за да покаже грешката. Голямото предимство тук е, че обработката на грешки е последователна. А ако съобщението трябва да се промени (например да се покаже допълнително номерът на грешката или да се регистрира грешката във файл), това трябва да се направи само на едно място. 

clsErrorHandler е модулът на класа, който прилага кода за обработване на грешки. Модулът на класа държи всичките си основни и помощни функции заедно в едно цяло, като по този начин капсулира кода.

Макросът AutoExec извиква функцията за стартиране в modStartup. В Starter Edition функцията създава екземпляр на clsErrorHandler и го записва като глобална променлива, която е достъпна за използване в цялото приложение. В изданието за разработчици се използва статичен клас – вижте коментарите в горната част на модула на класа.

Всъщност кодът за обработка на грешки в процедурите е толкова последователен, че успяхме да го създадем за по-малко от пет минути, използвайки специфичен VBA код, който оборудва всяка процедура с правилния манипулатор на грешки. (Кодът не е включен в шаблона). Шаблонните издания на Northwind 2.0 Starter и Developer първоначално са оборудвани с този подход за обработване на грешки. 
'

ПОДОБРЕНО ОБРАБОТВАНЕ НА ГРЕШКИ

Започвайки с версия 2.2 на Northwind Developer Edition, манипулаторът на грешки е подобрен благодарение на обратната връзка от общността на Access. Началното издание е непроменено. 

По същество манипулаторът на грешки в по-старата версия (2.0 – издадена през април 2023 г.) е:

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_Load и cmdPrintInvoice_Click.
    '

В допълнение към процедурите за събития, приложенията имат подпрограми и функции – най-вече в модули – и този код се извиква от процедурите за събития. Те се наричат "стандартни" процедури.

Във версия 2.0 на Northwind стандартните процедури ще обработват собствените си грешки със съобщения, но по някакъв начин няма да уведомят процедурата за повикващо събитие, че е възникнала грешка. Това може да е лошо, ако процедурата за събитие има следващ код, който трябва да се изпълни, независимо от предишната грешка, обработена от извиканата процедура. Разбира се, можем да заменим подпрограмата с функция, която връща успех или неуспех, и да кодираме процедурата за събитието по съответния начин, но това не винаги е опция.

В Northwind версия 2.2 стандартните процедури не обработват съобщения за грешка, а по-скоро чрез Err.Raise ги докладват обратно към процедурата за повикване на събитие. Процедурата за повикване на събитие след това показва възникналата грешка и се възобновява в Exit_Handler. Това е по-добре, защото позволява процедурата за повикване да приключи правилно.

За да използвате кода за версия 2.2 на Northwind, процедурите за обработка на събития трябва да подадат в HandleError трети аргумент, показващ, че викащият е процедура за събитие. Northwind Dev Edition е актуализиран, за да направи това.

Още по-мощен модул за обработка на грешки ще има поддръжка за процедури за "избутване и изскачане" на "стек" (масив). Първият елемент винаги ще бъде процедурата за събитие, така че допълнителният аргумент не е необходим. Тази реализация е извън целите на Northwind Dev Edition.

Списък на MRU

MRU, или последно използвани , е списък на последно използваните поръчки и поръчки за покупка. Можете често да се връщате към тях, за да ги поставите в следващото състояние. Списъците с MRU често се виждат в продуктите на Office като списък на последно използваните файлове, които може да искате да отворите отново.

В изданието Northwind Dev, за да приложите функцията MRU (която не съществува в изданието Starter), първо трябва да установите следните елементи:

  1. Таблица за съхраняване на информацията за MRU.
  2. Код за актуализиране на таблицата при отваряне на поръчка или поръчка за покупка (PO).
  3. Код за актуализиране на падащия списък на MRU в лентата.
  4. Код за зареждане на елемента, когато от лентата бъде избран елемент на MRU.

Нека разгледаме всяка от тях по-подробно. 

1. Таблица за съхраняване на информацията за MRU.

Дизайнът на таблицата MRU си заслужава да бъде прегледан, особено нейните индекси. Имайте предвид, че има дублиран индекс SortIdx , който помага за бързото сортиране на елементите на MRU в падащия списък на лентата, както и уникален индекс за налагане на бизнес правилото, според което за всеки потребител даден елемент може да се среща само веднъж. Например отварянето на една и съща поръчка два пъти не създава два записа в таблицата MRU.

Таблицата се възползва от факта, че всички свързани с MRU PK (първичен ключ) полета в базата данни са с автоматично номериране, така че типът данни Long Integer може да се използва за PKValue.

2. Код за актуализиране на таблицата при отваряне на поръчка или пощенска поддръжка.

В NW2 избрахме да добавяме към списъка MRU само когато е създаден нов запис, а не когато съществуващ е актуализиран отново. Със сигурност бихме могли да преместим обаждането на AddToMRU от Form_AfterInsert в Form_AfterUpdate , за да поддържаме това.

Процедурите AddToMRU и DeleteFromMRU са внедрени в modGlobal, който е Standard модул, чиито публични процедури са видими от всяка форма.

AddToMRU (както подсказва името) добавя новия елемент към таблицата MRU и след това по желание го изрязва обратно, изтривайки най-стария запис, ако е надхвърлил максималния размер (MAX_MRU_COUNT). Последната стъпка вероятно е най-малко известната на разработчиците на Access: падащото меню на лентата трябва да се обнови и това се извършва чрез извикване на InvalidateControl. Това е сигнал към лентата да изпълни отново процеса на инициализиране. 

3. Код за актуализиране на падащия списък MRU в лентата.

По време на стартиране и след като InvalidateControl е извикан, се изпълнява сложен набор от функции за попълване на лентата.  Тези процедури се извикани от XML на лентата в таблица uSysRibbons , в която отчасти се казва:


<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>

Тези четири функции за обратно повикване попълват падащия списък. Забележете, че това е почти същата идея, както е описана тук за стандартните разгъващи се списъци.

Ако премахнете коментара от редовете Debug.Print в modRibbonCallback и рестартирате приложението, непосредственият прозорец ще представи последователност като тази:


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 първо извиква процедура, която връща броя на елементите за зареждане в аргумента ByRef на ddMRU_GetItemCount. Това е и времето, когато отваряме заявката в таблицата на MRU и я кешираме, защото предстои да бъде използвана няколко пъти. 

След това лентата многократно извиква две процедури, за да получи стойностите на "ИД" и "Етикет" за падащия списък с две колони. 

И накрая, тя извиква процедура, за да се определи кой елемент трябва да бъде избран. (В нашия случай това е първият.)

4. Код за зареждане на елемент, когато елементът на MRU е избран от лентата.

Както при всеки друг елемент на лентата, свойството OnAction в XML на лентата указва функцията за обратно извикване, която да се използва за извършване на действието:


onAction="ddMRU_OnAction"

Тази процедура е реализирана в modRibbonCallback. Той използва повторно вече отворения набор записи, за да намери записа с избрания елемент, и след това, в зависимост от изискваното име на таблица, отваря съответния формуляр, предавайки стойността за PK за зареждане.

Научете повече