本教學課程會建立簡單的應用程式來管理客戶清單。 如此一來,它會針對UWP中的企業應用程式引進一系列基本概念。 您將瞭解如何:
- 針對本機 SQL 資料庫實作建立、讀取、更新和刪除作業。
- 新增數據格,以在UI中顯示和編輯客戶數據。
- 在基本表單配置中將UI元素排列在一起。
本教學課程的起點是一個單頁應用程式,其 UI 和功能最少,以 客戶訂單資料庫範例應用程式的簡化版本為基礎,。 它是以 C# 和 XAML 撰寫,我們預期您已基本熟悉這兩種語言。
先決條件
複製/下載存放庫之後,您可以使用 Visual Studio 開啟 CustomerDatabaseTutorial.sln 來編輯專案。
備註
本教學課程是以 客戶訂單資料庫範例 為基礎,該範例最近已更新為使用 WinUI 和 Windows App SDK。 在更新本教學課程和程序代碼之前,這兩個範例之間會有差異。
第 1 部分:感興趣的程式代碼
如果您在開啟應用程式之後立即執行,您會在空白畫面頂端看到一些按鈕。 雖然您無法看到,但應用程式已配備了一個包含幾個測試客戶的本機 SQLite 資料庫。 從這裡開始,您將從實作UI控制項來顯示這些客戶,然後繼續對資料庫新增作業。 開始之前,以下是您將工作的地方。
瀏覽次數
CustomerListPage.xaml 是應用程式的 View,它會定義本教學課程中單一頁面的 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 套件已包含在此專案中。 讓我們將網格線新增至專案。
從「Solution Explorer」開啟 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 資料庫擷取測試 Customer 數據。
在 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 方法的呼叫。 這可讓其連絡儲存庫以擷取可列舉的客戶物件集合。 然後,它會將它們剖析成個別物件,再將它們新增至其內部 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,用來保存新建立的客戶。
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; }
將下列程式代碼行新增為 setter 中 AddNewCustomer的最後一行:
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。
- 請提供遠端資料庫的網址,並放入 Constants.cs。
- 請將資料庫的連接字串提供給 Constants.cs。
- 將您的應用程式與 Microsoft 市集產生關聯。
- 將 Service 項目複製到您的應用程式,並將其部署至 Azure。
認證
您必須建立按鈕來啟動驗證流程,以及彈出視窗或個別頁面來收集用戶的資訊。 建立之後,您必須提供程式碼來要求使用者的資訊,並使用它來取得存取令牌。 客戶訂單資料庫範例使用 WebAccountManager 函式庫封裝對 Microsoft Graph 的呼叫,以獲取令牌並處理到 Azure Active Directory (AAD) 帳戶的身份驗證。
- 驗證邏輯會在 AuthenticationViewModel.cs中實作。
- 驗證程式會顯示在自定義 AuthenticationControl.xaml 控件中。
REST 呼叫
您不需要修改我們在本教學課程中新增的任何程序代碼,才能實作 REST 呼叫。 相反地,您必須執行下列動作:
- 建立 ICustomerRepository 和 ITutorialRepository 介面的新實作,透過 REST 實作相同的函式集,而不是 SQLite。 您需要將 JSON 序列化和反序列化,如果需要,可以將 REST API 呼叫包裝在個別的 HttpHelper 類別中。 如需詳細資訊,請參閱 完整的範例。
- 在 App.xaml.cs中,建立新的函式來初始化 REST 存放庫,並在應用程式初始化時呼叫它,而不是 SqliteDatabase。 再次,請參閱 完整的範例。
完成上述三個步驟之後,您應該能夠透過您的應用程式向 AAD 帳戶進行驗證。 遠端資料庫的 REST 呼叫將會取代本機 SQLite 呼叫,但使用者體驗應該相同。 如果您覺得更雄心勃勃,您可以新增設定頁面,讓使用者在兩者之間動態切換。