教學課程:建立客戶資料庫應用程式
本教學課程會建立一個簡單的應用程式來管理客戶清單。 為此,它會介紹 UWP 中企業應用程式的一系列基本概念。 您將學習如何:
- 對本機 SQL 資料庫實作建立、讀取、更新和刪除作業。
- 新增資料格,以在 UI 中顯示和編輯客戶資料。
- 將 UI 元素排列在基本表單佈局中。
本教程以具有最少 UI 和功能的單頁應用程序作為開頭,以簡化的客戶訂單資料庫範例應用程式版本為基礎。 它是以 C# 和 XAML 撰寫,我們預期您已基本熟悉這兩種語言。
必要條件
複製/下載存放庫之後,就可以使用 Visual Studio 開啟 CustomerDatabaseTutorial.sln 來編輯專案。
注意
本教學課程是以客戶訂單資料庫範例為基礎,該範例最近已更新為使用 WinUI 和 Windows 應用程式 SDK。 在本教學課程和程式碼更新之前,這兩個範例之間將會存在差異。
第 1 部分:興趣程式碼
如果您在打開應用程式後立即運行,您會在空白畫面頂端看到幾個按鈕。 雖然您看不到,但該應用程式已經包含一個由幾位測試客戶佈建的本機 SQLite 資料庫。 從這裡開始,您將先實作一個 UI 控制項來顯示這些客戶,然後繼續新增針對資料庫的作業。 在開始之前,以下是您將執行動作的地方。
檢視
CustomerListPage.xaml 是應用程式的視圖,其定義本教學課程中單一頁面的 UI。 每當您需要在 UI 中新增或變更視覺元素時,都可以在此檔案中完成。 本教學將引導您新增以下元素:
- RadDataGrid,用來顯示和編輯客戶。
- StackPanel,可設定新客戶的初始值。
ViewModels
ViewModels\CustomerListPageViewModel.cs,這是應用程式基本邏輯所在的位置。 在視圖中執行的每個使用者動作都會傳遞到此檔案中進行處理。 在本教程中,您將添加一些新程式碼,並實作以下方法:
- CreateNewCustomerAsync,初始化新的 CustomerViewModel 物件。
- DeleteNewCustomerAsync,它會先移除新客戶,再將其顯示在 UI 中。
- DeleteAndUpdateAsync,其可處理刪除按鈕的邏輯。
- GetCustomerListAsync,其會從資料庫擷取客戶清單。
- SaveInitialChangesAsync,其會將新的客戶資訊新增至資料庫。
- UpdateCustomersAsync,其會重新整理 UI,以反映任何新增或刪除的客戶。
CustomerViewModel,是客戶資訊的包裝函式,可追蹤它是否最近修改過。 您不需要向此類別添加任何內容,但您在其他地方添加的部分程式碼將引用它。
有關如何建構範例的詳細資訊,請參閱應用程序結構概觀。
第 2 部分:新增 DataGrid
開始對客戶資料進行操作之前,您需要新增一個 UI 控制項來顯示這些客戶。 若要這樣做,我們將使用預先製作的第三方 RadDataGrid 控制項。 Telerik.UI.for.UniversalWindowsPlatform NuGet 套件已包含在此專案中。 讓我們將網格線新增至專案。
從「方案總管」開啟 Views\CustomerListPage.xaml。 在 Page 標籤中新增以下程式代碼行,以宣告對應至包含數據格的 Telerik 命名空間。
xmlns:telerikGrid="using:Telerik.UI.Xaml.Controls.Grid"
在視圖的主要 RelativePanel 內的 CommandBar 下方,新增 RadDataGrid 控件,其中包含一些基本設定選項:
<Grid x:Name="CustomerListRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <RelativePanel> <CommandBar x:Name="mainCommandBar" HorizontalAlignment="Stretch" Background="AliceBlue"> <!--CommandBar content--> </CommandBar> <telerikGrid:RadDataGrid x:Name="DataGrid" BorderThickness="0" ColumnDataOperationsMode="Flyout" GridLinesVisibility="None" GroupPanelPosition="Left" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True" RelativePanel.Below="mainCommandBar" /> </RelativePanel> </Grid>
您已新增資料網格,但它需要資料才能顯示。 將以下程式碼行加入其中:
ItemsSource="{x:Bind ViewModel.Customers}" UserEditMode="Inline"
現在您已經定義了要顯示的資料來源,RadDataGrid 將為您處理大部分 UI 邏輯。 不過,如果您執行專案,仍然不會看到任何資料。 那是因為 ViewModel 尚未載入資料。
第 3 部分:閱讀客戶
初始化後,ViewModels\CustomerListPageViewModel.cs 會呼叫 GetCustomerListAsync 方法。 此方法需要從本教程中包含的 SQLite 資料庫檢索測試客戶資料。
在 ViewModels\CustomerListPageViewModel.cs 中,使用下列程式碼更新 GetCustomerListAsync 方法:
public async Task GetCustomerListAsync() { var customers = await App.Repository.Customers.GetAsync(); if (customers == null) { return; } await DispatcherHelper.ExecuteOnUIThreadAsync(() => { Customers.Clear(); foreach (var c in customers) { Customers.Add(new CustomerViewModel(c)); } }); }
載入 ViewModel 時會呼叫 GetCustomerListAsync 方法,但在此步驟之前,其不會執行任何動作。 在這裡,我們已在 Repository/SqlCustomerRepository 中新增 GetAsync 方法的呼叫。 這可讓其連絡存放庫以擷取 Customer 物件的可列舉集合。 然後,它會將它們剖析成個別物件,再將它們新增至其內部 ObservableCollection ,以便顯示和編輯它們。
執行您的應用程式 - 您現在會看到顯示客戶清單的資料格。
第 4 部分:編輯客戶
您可以按兩下資料格中的項目來進行編輯,但您必須確定您在 UI 中所做的任何變更也會對程式碼後置中的客戶集合進行變更。 這表示您必須實作雙向數據系結。 如果您想了解更多相關資訊,請參閱我們的數據系結簡介。
首先,宣告 ViewModels\CustomerListPageViewModel.cs 實作 INotifyPropertyChanged 介面:
public class CustomerListPageViewModel : INotifyPropertyChanged
然後,在類別的主體中,新增以下事件和方法:
public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
OnPropertyChanged 方法可讓您的 setter 輕鬆引發 PropertyChanged 事件,這對於雙向資料綁定是必要的。
使用下列函數呼叫更新 SelectedCustomer 的 setter:
public CustomerViewModel SelectedCustomer { get => _selectedCustomer; set { if (_selectedCustomer != value) { _selectedCustomer = value; OnPropertyChanged(); } } }
在 Views\CustomerListPage.xaml 中,將 SelectedCustomer 屬性新增至您的數據格。
SelectedItem="{x:Bind ViewModel.SelectedCustomer, Mode=TwoWay}"
這會將資料網格中的使用者選擇與程式碼隱藏中對應的 Customer 物件相關聯。 TwoWay 綁定模式可讓您在 UI 中所做的變更反映在該物件上。
執行應用程式。 現在您可以查看網格中顯示的客戶,並透過 UI 對基礎資料進行變更。
第 5 部分:更新客戶
現在您可以查看和編輯客戶,您需要能夠將變更推送到資料庫,並提取其他人所做的任何更新。
返回 ViewModels\CustomerListPageViewModel.cs,然後流覽至 UpdateCustomersAsync 方法。 使用以下程式碼進行更新,將變更推送到資料庫並檢索任何新資訊:
public async Task UpdateCustomersAsync() { foreach (var modifiedCustomer in Customers .Where(x => x.IsModified).Select(x => x.Model)) { await App.Repository.Customers.UpsertAsync(modifiedCustomer); } await GetCustomerListAsync(); }
此程式代碼會利用 ViewModels\CustomerViewModel.cs 的 IsModified 屬性,每當客戶變更時就會自動更新。 這可讓您避免不必要的呼叫,並只將更新的客戶變更推送至資料庫。
第 6 部分:建立新客戶
新增客戶是一項挑戰,因為如果您在為其屬性提供值之前將其新增至 UI,則該客戶將顯示為空白行。 這不是個問題,但在這裡,我們將能更輕鬆設定客戶的初始值。 在本教學課程中,我們將新增簡單的可折疊面板,但如果您有更多資訊要新增,您可以為此一個單獨的頁面。
更新程式碼後置
將新的私人欄位和公用屬性新增至 ViewModels\CustomerListPageViewModel.cs。 這會用來控制面板是否可見。
private bool _addingNewCustomer = false; public bool AddingNewCustomer { get => _addingNewCustomer; set { if (_addingNewCustomer != value) { _addingNewCustomer = value; OnPropertyChanged(); } } }
在 ViewModel 新增一個新的公用屬性,該屬性與 AddingNewCustomer 的值相反。 當面板可見時,這將用於停用一般命令列按鈕。
public bool EnableCommandBar => !AddingNewCustomer;
現在您需要一種方法來顯示可折疊面板,並建立一個客戶以在其中進行編輯。
在 ViewModel 新增一個新的私人 fiend 和公用屬性,以儲存新建立的客戶。
private CustomerViewModel _newCustomer; public CustomerViewModel NewCustomer { get => _newCustomer; set { if (_newCustomer != value) { _newCustomer = value; OnPropertyChanged(); } } }
更新 CreateNewCustomerAsync 方法以建立新的客戶、將其新增至存放庫,並將其設為已選取的客戶:
public async Task CreateNewCustomerAsync() { CustomerViewModel newCustomer = new CustomerViewModel(new Models.Customer()); NewCustomer = newCustomer; await App.Repository.Customers.UpsertAsync(NewCustomer.Model); AddingNewCustomer = true; }
更新 SaveInitialChangesAsync 方法,將新建立的客戶新增至存放庫、更新 UI,然後關閉面板。
public async Task SaveInitialChangesAsync() { await App.Repository.Customers.UpsertAsync(NewCustomer.Model); await UpdateCustomersAsync(); AddingNewCustomer = false; }
將以下程式碼行新增為 AddingNewCustomer 中 setter 的最後一行:
OnPropertyChanged(nameof(EnableCommandBar));
這將確保每當 AddingNewCustomer 發生變更時,EnableCommandBar 都會自動更新。
更新 UI
導覽回 Views\CustomerListPage.xaml,並在 CommandBar 和資料網格之間新增具有以下屬性的 StackPanel:
<StackPanel x:Name="newCustomerPanel" Orientation="Horizontal" x:Load="{x:Bind ViewModel.AddingNewCustomer, Mode=OneWay}" RelativePanel.Below="mainCommandBar"> </StackPanel>
x:Load 屬性可確保只有在您新增客戶時,才會顯示此面板。
對資料網格的位置進行以下更改,以確保它在新面板出現時向下移動:
RelativePanel.Below="newCustomerPanel"
使用四個 TextBox 控制件更新堆疊面板。 它們將綁定到新客戶的各個屬性,並可讓您在將其新增至資料網格之前編輯其值。
<StackPanel x:Name="newCustomerPanel" Orientation="Horizontal" x:Load="{x:Bind ViewModel.AddingNewCustomer, Mode=OneWay}" RelativePanel.Below="mainCommandBar"> <TextBox Header="First name" PlaceholderText="First" Margin="8,8,16,8" MinWidth="120" Text="{x:Bind ViewModel.NewCustomer.FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <TextBox Header="Last name" PlaceholderText="Last" Margin="0,8,16,8" MinWidth="120" Text="{x:Bind ViewModel.NewCustomer.LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <TextBox Header="Address" PlaceholderText="1234 Address St, Redmond WA 00000" Margin="0,8,16,8" MinWidth="280" Text="{x:Bind ViewModel.NewCustomer.Address, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <TextBox Header="Company" PlaceholderText="Company" Margin="0,8,16,8" MinWidth="120" Text="{x:Bind ViewModel.NewCustomer.Company, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel>
在新的堆疊面板中新增一個簡單的按鈕,以儲存新建立的客戶:
<StackPanel> <!--Text boxes from step 3--> <AppBarButton x:Name="SaveNewCustomer" Click="{x:Bind ViewModel.SaveInitialChangesAsync}" Icon="Save"/> </StackPanel>
更新 CommandBar,以便當堆疊面板可見時停用一般建立、刪除和更新按鈕:
<CommandBar x:Name="mainCommandBar" HorizontalAlignment="Stretch" IsEnabled="{x:Bind ViewModel.EnableCommandBar, Mode=OneWay}" Background="AliceBlue"> <!--App bar buttons--> </CommandBar>
執行應用程式。 您現在可以建立客戶,並在堆疊面板中輸入其數據。
第 7 部分:刪除客戶
刪除客戶是您需要實作的最後一個基本作業。 當您刪除在資料格中選取的客戶時,您需要立即呼叫 UpdateCustomersAsync 以更新 UI。 但是,如果您要刪除剛剛建立的客戶,則無需呼叫該方法。
流覽至 ViewModels\CustomerListPageViewModel.cs,並更新 DeleteAndUpdateAsync 方法:
public async void DeleteAndUpdateAsync() { if (SelectedCustomer != null) { await App.Repository.Customers.DeleteAsync(_selectedCustomer.Model.Id); } await UpdateCustomersAsync(); }
在 Views\CustomerListPage.xaml 中,更新用於新增客戶的堆疊面板,使其包含第二個按鈕:
<StackPanel> <!--Text boxes for adding a new customer--> <AppBarButton x:Name="DeleteNewCustomer" Click="{x:Bind ViewModel.DeleteNewCustomerAsync}" Icon="Cancel"/> <AppBarButton x:Name="SaveNewCustomer" Click="{x:Bind ViewModel.SaveInitialChangesAsync}" Icon="Save"/> </StackPanel>
在 ViewModels\CustomerListPageViewModel.cs中 ,更新 DeleteNewCustomerAsync 方法來刪除新客戶:
public async Task DeleteNewCustomerAsync() { if (NewCustomer != null) { await App.Repository.Customers.DeleteAsync(_newCustomer.Model.Id); AddingNewCustomer = false; } }
執行應用程式。 您現在可以在資料格內或堆疊面板中刪除客戶。
結論
恭喜! 完成這一切之後,您的應用程式現在已擁有完整的本機資料庫作業。 您可以在 UI 內建立、讀取、更新和刪除客戶,這些變更會儲存至您的資料庫,並會在應用程式的不同啟動中持續存在。
現在您已完成整個流程,請考慮下列事項:
- 如果您還沒有這樣做,請查看應用程式結構概觀,以獲取有關應用程式為何如此構建的更多資訊。
- 探索完整的客戶訂單資料庫範例,以了解本教學課程所根據的應用程式。
或者,如果您準備好迎接挑戰,您可以繼續前進...
進一步:連線至遠端資料庫
我們已逐步解說如何針對本機 SQLite 資料庫實作這些呼叫。 但如果您想要改用遠端資料庫,該怎麼辦?
如果您想嘗試一下,您需要自己的 Azure Active Directory (AAD) 帳戶,以及託管資料來源的能力。
您需要新增驗證、處理 REST 呼叫的函數,然後建立一個遠端資料庫進行互動。 完整的客戶訂單資料庫範例中有程式碼,您可以參考每個必要的作業。
設定與組態
範例的自述文件中詳細說明了連接到您遠端資料庫的必要步驟。 您需要執行下列作業:
- 將您的 Azure 帳戶用戶端識別碼提供給 Constants.cs。
- 將遠端資料庫的 URL 提供給 Constants.cs。
- 向 Constants.cs 提供資料庫的連線字串。
- 將您的應用程式與 Microsoft Store 關聯。
- 將服務專案複製到您的應用程式中,並將其部署到 Azure。
驗證
您需要建立一個按鈕來啟動驗證序列,並建立一個快顯視窗或單獨的頁面來收集使用者資訊。 建立之後,您必須提供程式碼來要求使用者的資訊,並使用其來取得存取令牌。 客戶訂單資料庫範例會使用 WebAccountManager 程式庫包裝 Microsoft Graph 呼叫,以取得令牌並處理 AAD 帳戶的驗證。
- 驗證邏輯會在 AuthenticationViewModel.cs 中實作。
- 驗證程序會顯示在自訂 AuthenticationControl.xaml 控件中。
REST 呼叫
您無需修改我們在本教程中新增的任何程式碼即可實作 REST 呼叫。 但您需要執行下列作業:
- 建立 ICustomerRepository 和 ITutorialRepository 介面的新實作,透過 REST 而不是 SQLite 實作相同的函數集。 您需要序列化和反序列化 JSON,並且如果需要,可以將 REST 呼叫包裝在單獨的 HttpHelper 類別中。 有關詳細資訊,請參閱完整範例。
- 在 App.xaml.cs 中,建立一個新函數來初始化 REST 儲存庫,並在初始化應用程式時呼叫它,而不是 SqliteDatabase。 同樣地,請參閱完整的範例。
完成上述三個步驟之後,您應該能夠透過應用程式對 AAD 帳戶進行驗證。 對遠端資料庫的 REST 呼叫將會取代本機 SQLite 呼叫,但使用者體驗應該是相同的。 如果您想更進一步,則可以新增設定頁面,讓使用者在兩者之間動態切換。