Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124

延伸文章 建立一個在 Business Central 裡獨立運行的應用程式(CRUD) 中的運用,在 Name 欄位 → 開窗查詢 User 資料(例如從系統 User 表或自訂表)→ 選取後自動把使用者的名稱與描述帶回當前記錄。
在 AL Page 裡可以使用:
TableRelation → 建立 Lookup 關聯OnValidate() 或 OnLookup() → 自訂選取邏輯與資料回填可以用「系統內建的 User 表」(User table, ID = 2000000120) 作為範例。
page 60100 "Basic Table Page"
{
PageType = List;
ApplicationArea = All;
SourceTable = "Basic Table";
UsageCategory = Lists; // 讓它可以從搜尋直接找到
layout
{
area(content)
{
repeater(Group)
{
field(ID; Rec."ID")
{
ApplicationArea = All;
Editable = false;
}
field(Name; Rec."Name")
{
ApplicationArea = All;
}
field(Description; Rec."Description")
{
ApplicationArea = All;
}
field("User ID"; Rec."User ID")
{
ApplicationArea = All;
Caption = 'User';
TableRelation = User."User Security ID"; // 建立查詢來源
trigger OnLookup(var Text: Text): Boolean
var
UserRec: Record User;
begin
// 開啟使用者清單供選擇
if PAGE.RunModal(PAGE::"Users", UserRec) = ACTION::LookupOK then begin
Rec."User ID" := UserRec."User Security ID";
Rec."Name" := UserRec."User Name";
Rec."Description" := UserRec."Full Name";
end;
exit(true); // 告訴系統這個 lookup 已被處理
end;
}
}
}
}
}User ID 欄位 → 系統開啟內建的 Users 頁面。UserRec。UserRec 的欄位值(User Name, Full Name)帶回當前記錄:Rec."Name" := UserRec."User Name";
Rec."Description" := UserRec."Full Name";若你想用自訂的 User 表(例如 Employee 或 Customer),只要:
UserRec 改成你的資料表記錄變數;PAGE.RunModal(PAGE::"Users", UserRec) 改成對應的頁面名稱;這樣部署後:
Hello World Page 點選 User ID → 開窗顯示使用者清單Name、Description 欄位新增一個欄位,似乎是多此一舉,改成「使用者點擊 Name 欄位 → 開啟系統內建的 Users 頁面 → 選取使用者 → 自動回填 Name 與 Description 欄位」而且 不增加 User ID 欄位。
在 AL 中可以用:
trigger OnLookup() 自訂查詢視窗PAGE.RunModal() 開啟使用者頁面Rec 記錄物件寫入值page 60100 "Basic Table Page"
{
PageType = List;
ApplicationArea = All;
SourceTable = "Basic Table";
UsageCategory = Lists; // 讓它可以從搜尋直接找到
layout
{
area(content)
{
repeater(Group)
{
field(ID; Rec."ID")
{
ApplicationArea = All;
Editable = false;
}
field(Name; Rec."Name")
{
ApplicationArea = All;
Lookup = true;
trigger OnLookup(var Text: Text): Boolean
var
UserRec: Record User;
ConfirmReplace: Boolean;
begin
if PAGE.RunModal(PAGE::Users, UserRec) = ACTION::LookupOK then begin
Rec."Name" := UserRec."User Name";
if Rec."Description" <> '' then begin
ConfirmReplace := Dialog.Confirm(
'此筆資料已有描述 (%1),是否要覆寫為 "%2"?',
false,
Rec."Description",
UserRec."Full Name"
);
if ConfirmReplace then
Rec."Description" := UserRec."Full Name";
end else
Rec."Description" := UserRec."Full Name";
end else begin
// 使用者取消選取 → 清空欄位
Rec."Name" := '';
Rec."Description" := '';
end;
CurrPage.Update();
exit(true);
end;
}
field(Description; Rec."Description")
{
ApplicationArea = All;
}
}
}
}
}PAGE::Users 是系統保留常數,可直接使用。AL: Download Symbols 已執行;Editable = false; 即可。執行的畫面如下:

執行後,可以發現 Name 的值並沒有更新,而是空白,在 OnLookup 觸發器中,讓 Name 欄位在使用者選擇後,正確顯示所選使用者的名稱。根據上面的程式碼,在 OnLookup 觸發器中執行了以下動作:
PAGE::Users) 供使用者選擇。User Name 欄位值賦予給當前記錄的 Name 欄位 (Rec."Name" := UserRec."User Name";)。問題在於,當你在 OnLookup 觸發器中成功取得並賦值給 Rec."Name" 後,你需要確保這個新的值能夠被顯示出來。由於你已經設定了 exit(true); 並且呼叫了 CurrPage.Update();,照理說欄位會被更新。
然而,AL 語言中對於 OnLookup 觸發器的行為是:
OnLookup 中返回 true,表示已經處理了查找 (lookup) 動作,並且 系統不會再執行預設的查找動作。exit(true); 時,需要手動將選取的值帶回給 Text 變數 (也就是欄位原本的值) 才能讓頁面欄位顯示新值。但程式碼已經直接修改了 Rec."Name",所以這部分邏輯是正確的。已經使用了 CurrPage.Update() 來更新頁面,這通常是足夠的。
最可能的原因是 field(Name; Rec."Name") 的 OnLookup 觸發器 雖然修改了 Rec."Name" 的值,但該值在離開觸發器後可能沒有被正確地寫入頁面控制項,特別是在列表頁上。
要確保選取的值能被正確地帶回並顯示在欄位中,需要在 OnLookup 觸發器的開頭使用傳入的 Text 參數 來設定回傳值,並在成功選擇後,將新的值賦予給這個 Text 變數。
page 60100 "Basic Table Page"
{
PageType = List;
ApplicationArea = All;
SourceTable = "Basic Table";
UsageCategory = Lists; // 讓它可以從搜尋直接找到
layout
{
area(content)
{
repeater(Group)
{
field(ID; Rec."ID")
{
ApplicationArea = All;
Editable = false;
}
field(Name; Rec."Name")
{
ApplicationArea = All;
Lookup = true;
trigger OnLookup(var Text: Text): Boolean // <--- 注意這裡的 Text 參數
var
UserRec: Record User;
ConfirmReplace: Boolean;
begin
// **修正步驟 1: 將選取邏輯獨立出來**
if PAGE.RunModal(PAGE::Users, UserRec) = ACTION::LookupOK then begin
// **修正步驟 2: 將選取到的使用者名稱賦值給 Rec 欄位**
Rec."Name" := UserRec."User Name"; // 確定這是你希望儲存的欄位
// **修正步驟 3: 將新的值賦予給 Text 參數**
// 這是確保在 OnLookup 結束後,欄位顯示新值的關鍵步驟
Text := Rec."Name";
// 接著處理 Description 欄位更新邏輯
if Rec."Description" <> '' then begin
ConfirmReplace := Dialog.Confirm(
'此筆資料已有描述 (%1),是否要覆寫為 "%2"?',
false,
Rec."Description",
UserRec."Full Name"
);
if ConfirmReplace then
Rec."Description" := UserRec."Full Name";
end else
Rec."Description" := UserRec."Full Name";
// **修正步驟 4: 移除 CurrPage.Update()**
// 通常情況下,當 OnLookup 傳回 true 且 Text 參數有值時,
// 系統會自動更新欄位。
// 在 List 頁面上,頻繁呼叫 CurrPage.Update()
// 可能會導致效能問題或意外行為。
exit(true); // 傳回 true 表示你已經處理了查找動作
end else begin
// 使用者取消選取 → 清空欄位
Rec."Name" := '';
Rec."Description" := '';
Text := ''; // 同時清空 Text 參數
exit(true); // 傳回 true
end;
// 舊的 CurrPage.Update() 已經不需要了
// CurrPage.Update();
// exit(true); // 已經在 if/else 區塊中處理
end;
}
field(Description; Rec."Description")
{
ApplicationArea = All;
}
}
}
}
}在 OnLookup 觸發器中加入了以下關鍵行:
Text := Rec."Name";OnLookup 觸發器的 Text 參數是一個 var (by reference) 變數,它代表了欄位的最終顯示值。Rec."Name"),但要讓頁面控制項立即顯示這個新值,你必須將這個值也賦予給 Text 變數。CurrPage.Update();OnLookup 傳回 true 時,頁面控制項通常會自動使用 Text 變數的值進行更新。在列表頁上,手動呼叫 CurrPage.Update() 有時會干擾這個自動流程,或導致不必要的頁面重繪。透過正確設定 Text 參數並 exit(true),可以依賴 AL 的內建機制來處理。這樣修改後,當使用者從 “Users” 頁面選擇一個使用者時,Rec."Name" 會被設定,同時 Text 變數也會被設定,確保名稱會立即顯示在頁面上的 Name 欄位中。