次の方法で共有


チュートリアル: 顧客データベース アプリケーションの作成

このチュートリアルでは、顧客の一覧を管理するための簡単なアプリを作成します。 その際に、UWP のエンタープライズ アプリの基本的な概念を紹介します。 次の方法について学習します。

  • ローカル SQL データベースに対して作成、読み取り、更新、および削除操作を実装します。
  • UI で顧客データを表示および編集するためのデータ グリッドを追加します。
  • 基本的なフォーム レイアウトで UI 要素を一緒に配置します。

このチュートリアルの開始点は、Customer Orders Database サンプル アプリの簡略化されたバージョンに基づいて、最小限の UI と機能を備えたシングルページ アプリです。 これは C# と XAML で記述されており、これらの両方の言語に関する基本的な知識があることを期待しています。

作業アプリのメイン ページ

[前提条件]

リポジトリを複製またはダウンロードしたら、Visual Studio で CustomerDatabaseTutorial.sln を開いてプロジェクトを編集できます。

このチュートリアルは、WinUI と Windows App SDK を利用するために最近更新された Customer Orders Database サンプル に基づいています。 このチュートリアルとコードが更新されるまで、2 つのサンプルに違いがあります。

パート 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 パッケージは既にこのプロジェクトに含まれています。 プロジェクトにグリッドを追加しましょう。

  1. ソリューション エクスプローラーから Views\CustomerListPage.xaml を開きます。 Page タグ内に次のコード行を追加して、データ グリッドを含む Telerik 名前空間へのマッピングを宣言します。

        xmlns:telerikGrid="using:Telerik.UI.Xaml.Controls.Grid"
    
  2. ビューのメイン 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>
    
  3. データ グリッドを追加しましたが、表示するにはデータが必要です。 次のコード行を追加します。

    ItemsSource="{x:Bind ViewModel.Customers}"
    UserEditMode="Inline"
    

    表示するデータのソースを定義したら、RadDataGrid によってほとんどの UI ロジックが処理されます。 ただし、プロジェクトを実行しても、データは表示されません。 これは、ViewModel がまだ読み込まれていないためです。

顧客がいない空のアプリ

パート 3: 顧客について理解する

初期化されると、ViewModels\CustomerListPageViewModel.cs は、GetCustomerListAsync メソッドを呼び出します。 このメソッドは、チュートリアルに含まれている SQLite データベースからテスト顧客データを取得する必要があります。

  1. 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));
            }
        });
    }
    

    GetCustomerListAsync メソッドは、ViewModel が読み込まれるときに呼び出されますが、この手順の前は何も行われませんでした。 ここでは、Repository/SqlCustomerRepositoryGetAsync メソッドの呼び出しを追加しました。 これにより、リポジトリに接続して Customer オブジェクトの列挙可能なコレクションを取得できます。 次に、それらを個別のオブジェクトに解析してから、内部 ObservableCollection に追加して、表示および編集できるようにします。

  2. アプリを実行する - データ グリッドに顧客の一覧が表示されます。

顧客 の初期リスト

パート 4: 顧客を編集する

データ グリッド内のエントリはダブルクリックして編集できますが、UI で行った変更が、分離コード内の顧客のコレクションにも行われるようにする必要があります。 つまり、双方向データ バインディングを実装する必要があります。 詳細については、のデータ バインディングの紹介を参照してください。

  1. 最初に、ViewModels\CustomerListPageViewModel.csINotifyPropertyChanged インターフェイスを実装することを宣言します。

    public class CustomerListPageViewModel : INotifyPropertyChanged
    
  2. 次に、クラスの本体内に、次のイベントとメソッドを追加します。

    public event PropertyChangedEventHandler PropertyChanged;
    
    public void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

    OnPropertyChanged メソッドを使用すると、セッターは双方向データ バインディングに必要な PropertyChanged イベントを簡単に発生できます。

  3. 次の関数呼び出し SelectedCustomer のセッターを更新します。

    public CustomerViewModel SelectedCustomer
    {
        get => _selectedCustomer;
        set
        {
            if (_selectedCustomer != value)
            {
                _selectedCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  4. Views\CustomerListPage.xamlで、SelectedCustomer プロパティをデータ グリッドに追加します。

    SelectedItem="{x:Bind ViewModel.SelectedCustomer, Mode=TwoWay}"
    

    これにより、データ グリッド内のユーザーの選択が、分離コード内の対応する Customer オブジェクトに関連付けられます。 TwoWay バインド モードを使用すると、UI で行われた変更をそのオブジェクトに反映できます。

  5. アプリを実行します。 これで、顧客がグリッドに表示され、UI を使用して基になるデータに変更を加えることができます。

データ グリッド で顧客を編集する

パート 5: 顧客を更新する

顧客を表示および編集できるようになったので、変更をデータベースにプッシュし、他のユーザーによって行われた更新をプルできる必要があります。

  1. 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.csIsModified プロパティを使用します。このプロパティは、顧客が変更されるたびに自動的に更新されます。 これにより、不要な呼び出しを回避し、更新された顧客からの変更のみをデータベースにプッシュできます。

パート 6: 新しい顧客を作成する

新しい顧客を追加すると、そのプロパティの値を指定する前に UI に追加すると、顧客が空白行として表示されるため、課題が発生します。 これは問題ではありませんが、ここでは、顧客の初期値を簡単に設定できるようにします。 このチュートリアルでは、簡単な折りたたみ可能なパネルを追加しますが、追加する詳細情報がある場合は、この目的のために別のページを作成できます。

コードビハインドを更新する

  1. ViewModels\CustomerListPageViewModel.csに新しいプライベートフィールドとパブリックプロパティを追加します。 これは、パネルが表示されるかどうかを制御するために使用されます。

    private bool _addingNewCustomer = false;
    
    public bool AddingNewCustomer
    {
        get => _addingNewCustomer;
        set
        {
            if (_addingNewCustomer != value)
            {
                _addingNewCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  2. ViewModel に新しいパブリックプロパティを追加します。このプロパティは、AddingNewCustomer の値の逆である です。 これは、パネルが表示されているときに通常のコマンド バー ボタンを無効にするために使用されます。

    public bool EnableCommandBar => !AddingNewCustomer;
    

    折りたたみ可能なパネルを表示し、その中で編集する顧客を作成する方法が必要になります。

  3. 新しく作成された顧客を保持するために、ViewModel に新しいプライベート ファイエンドとパブリック プロパティを追加します。

    private CustomerViewModel _newCustomer;
    
    public CustomerViewModel NewCustomer
    {
        get => _newCustomer;
        set
        {
            if (_newCustomer != value)
            {
                _newCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  4. CreateNewCustomerAsync メソッドを更新して、新しい顧客を作成し、それをリポジトリに追加し、選択した顧客として設定します。

    public async Task CreateNewCustomerAsync()
    {
        CustomerViewModel newCustomer = new CustomerViewModel(new Models.Customer());
        NewCustomer = newCustomer;
        await App.Repository.Customers.UpsertAsync(NewCustomer.Model);
        AddingNewCustomer = true;
    }
    
  5. SaveInitialChangesAsync メソッドを更新して、新しく作成した顧客をリポジトリに追加し、UI を更新して、パネルを閉じます。

    public async Task SaveInitialChangesAsync()
    {
        await App.Repository.Customers.UpsertAsync(NewCustomer.Model);
        await UpdateCustomersAsync();
        AddingNewCustomer = false;
    }
    
  6. 次のコード行を、AddingNewCustomerのセッターの最後の行として追加します。

    OnPropertyChanged(nameof(EnableCommandBar));
    

    これにより、 EnableCommandBar は、AddingNewCustomer が変更されるたびに自動的に更新されます。

UI を更新する

  1. 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 属性を使用すると、新しい顧客を追加するときにのみこのパネルが表示されます。

  2. 新しいパネルが表示されたときにデータ グリッドが下に移動するように、データ グリッドの位置を次のように変更します。

    RelativePanel.Below="newCustomerPanel"
    
  3. 4 つの 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>
    
  4. 新しいスタック パネルに単純なボタンを追加して、新しく作成した顧客を保存します。

    <StackPanel>
        <!--Text boxes from step 3-->
        <AppBarButton
            x:Name="SaveNewCustomer"
            Click="{x:Bind ViewModel.SaveInitialChangesAsync}"
            Icon="Save"/>
    </StackPanel>
    
  5. CommandBarを更新して、スタック パネルが表示されているときに通常の作成、削除、および更新ボタンが無効になるようにします。

    <CommandBar
        x:Name="mainCommandBar"
        HorizontalAlignment="Stretch"
        IsEnabled="{x:Bind ViewModel.EnableCommandBar, Mode=OneWay}"
        Background="AliceBlue">
        <!--App bar buttons-->
    </CommandBar>
    
  6. アプリを実行します。 これで、顧客を作成し、そのデータをスタック パネルに入力できるようになりました。

新しい顧客 の作成

パート 7: 顧客を削除する

顧客の削除は、実装する必要がある最後の基本的な操作です。 データ グリッド内で選択した顧客を削除すると、UI を更新するために、UpdateCustomersAsync すぐに呼び出す必要があります。 ただし、先ほど作成した顧客を削除する場合は、そのメソッドを呼び出す必要はありません。

  1. ViewModels\CustomerListPageViewModel.csに移動し、DeleteAndUpdateAsync メソッドを更新します。

    public async void DeleteAndUpdateAsync()
    {
        if (SelectedCustomer != null)
        {
            await App.Repository.Customers.DeleteAsync(_selectedCustomer.Model.Id);
        }
        await UpdateCustomersAsync();
    }
    
  2. Views\CustomerListPage.xamlで、新しい顧客を追加するためのスタック パネルを更新して、2 つ目のボタンが含まれるようにします。

    <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>
    
  3. ViewModels\CustomerListPageViewModel.csで、DeleteNewCustomerAsync メソッドを更新して、新しい顧客を削除します。

    public async Task DeleteNewCustomerAsync()
    {
        if (NewCustomer != null)
        {
            await App.Repository.Customers.DeleteAsync(_newCustomer.Model.Id);
            AddingNewCustomer = false;
        }
    }
    
  4. アプリを実行します。 データ グリッド内またはスタック パネルで、顧客を削除できるようになりました。

新しい顧客 を削除する

結論

おめでとうございます! これで、アプリにローカル データベース操作の全範囲が追加されました。 UI 内で顧客の作成、読み取り、更新、削除を行うことができます。これらの変更はデータベースに保存され、さまざまなアプリの起動間で保持されます。

これで完了です。次のことを検討してください。

または、課題に直面している場合は、次の手順に進むことができます。

さらに進む: リモート データベースに接続する

ローカル SQLite データベースに対してこれらの呼び出しを実装する方法の詳細なチュートリアルを提供しました。 しかし、代わりにリモート データベースを使用する場合はどうでしょうか。

これを試す場合は、独自の Azure Active Directory (AAD) アカウントと、独自のデータ ソースをホストする機能が必要です。

認証、REST 呼び出しを処理する関数を追加し、対話するリモート データベースを作成する必要があります。 Customer Orders Database の完全なサンプル には、必要な操作ごとに参照できるコードがあります。

設定と構成

独自のリモート データベースに接続するために必要な手順は、サンプルの readmeに記載されています。 次の操作を行う必要があります。

  • Constants.csに Azure アカウントのクライアント ID を指定します。
  • リモート データベース用の URL を Constants.csに指定します。
  • Constants.csに、データベースの接続文字列を提供します。
  • アプリを Microsoft Store に関連付けます。
  • Service プロジェクト をアプリにコピーし、Azure にデプロイします。

認証

認証シーケンスを開始するボタンと、ユーザーの情報を収集するためのポップアップまたは別のページを作成する必要があります。 作成したら、ユーザーの情報を要求し、それを使用してアクセス トークンを取得するコードを提供する必要があります。 Customer Orders Database サンプルは、トークンを取得し、AAD アカウントへの認証を処理するために、WebAccountManager ライブラリで Microsoft Graph 呼び出しをラップします。

REST 呼び出し

REST 呼び出しを実装するために、このチュートリアルで追加したコードを変更する必要はありません。 代わりに、次の操作を行う必要があります。

  • ICustomerRepositoryITutorialRepository インターフェイスの新しい実装を作成し、SQLite ではなく REST を介して同じ関数のセットを実装します。 JSON をシリアル化および逆シリアル化する必要があります。必要に応じて、別の HttpHelper クラスで REST 呼び出しをラップできます。 詳細については、完全なサンプル を参照してください。
  • App.xaml.csで、REST リポジトリを初期化する新しい関数を作成し、アプリの初期化時に SqliteDatabase ではなく、それを呼び出します。 ここでも、完全なサンプル参照してください。

これらの 3 つの手順がすべて完了すると、アプリを通じて AAD アカウントに対して認証できるようになります。 リモート データベースへの REST 呼び出しによってローカル SQLite 呼び出しが置き換えられますが、ユーザー エクスペリエンスは同じである必要があります。 さらに意欲的な場合は、設定ページを追加して、ユーザーが 2 つを動的に切り替えることができるようにすることができます。