Condividi tramite


Esercitazione: Creare un'applicazione di database dei clienti

Questa esercitazione consente di creare una semplice app per la gestione di un elenco di clienti. In questo modo, essa introduce una selezione di concetti di base per le app aziendali in UWP. Si apprenderà come:

  • Implementare operazioni di creazione, lettura, aggiornamento ed eliminazione in un database SQL locale.
  • Aggiungere una griglia dati per visualizzare e modificare i dati dei clienti nell'interfaccia utente.
  • Disporre gli elementi dell'interfaccia utente in un layout di modulo di base.

Il punto di partenza per questa esercitazione è un'app a pagina singola con interfaccia utente e funzionalità minime, in base a una versione semplificata dell'app di esempio Database ordini cliente. È scritta in C# e XAML e si presuppone la familiarità di base con entrambi i linguaggi.

Pagina principale dell'app funzionante

Prerequisiti

Dopo aver clonato o scaricato il repository, puoi modificare il progetto aprendo CustomerDatabaseTutorial.sln con Visual Studio.

Nota

Questa esercitazione si basa sull'esempio di database degli ordini cliente che è stato recentemente aggiornato per usare WinUI e l'SDK per app di Windows. Fino al momento in cui questa esercitazione e il codice non saranno aggiornati, vi saranno differenze tra i due esempi.

Parte 1: Codice di interesse

Eseguendo l'app immediatamente dopo l'apertura, vedrai alcuni pulsanti nella parte superiore di una schermata vuota. Anche se non è visibile, l'app include già un database SQLite locale di cui è stato effettuato il provisioning con alcuni clienti di test. Da qui si inizierà implementando un controllo dell'interfaccia utente per visualizzare i clienti e quindi passare all'aggiunta di operazioni nel database. Prima di iniziare, ecco dove lavorerai.

Visualizzazioni

CustomerListPage.xaml è la Vista dell'app che definisce l'interfaccia utente per la singola pagina in questa esercitazione. Ogni volta che devi aggiungere o modificare un elemento visivo nell'interfaccia utente, ciò sarà eseguito in questo file. Questa esercitazione illustra come aggiungere questi elementi:

  • RadDataGrid per la visualizzazione e la modifica dei clienti.
  • StackPanel per impostare i valori iniziali per un nuovo cliente.

ViewModel

ViewModels\CustomerListPageViewModel.cs è la posizione in cui si trova la logica fondamentale dell'app. Ogni azione eseguita dall'utente nella visualizzazione verrà passata a questo file per l'elaborazione. In questa esercitazione si aggiungeranno alcuni nuovi codici e si implementeranno i metodi seguenti:

  • CreateNewCustomerAsync, che inizializza un nuovo oggetto CustomerViewModel.
  • DeleteNewCustomerAsync, che rimuove un nuovo cliente prima che venga visualizzato nell'interfaccia utente.
  • DeleteAndUpdateAsync, che gestisce la logica del pulsante di eliminazione.
  • GetCustomerListAsync, che recupera un elenco di clienti dal database.
  • SaveInitialChangesAsync, che aggiunge le informazioni di un nuovo cliente al database.
  • UpdateCustomersAsync, che aggiorna l'interfaccia utente in modo da riflettere tutti i clienti aggiunti o eliminati.

CustomerViewModel è un wrapper per le informazioni su un cliente, che tiene traccia del fatto che sia stato modificato di recente o no. Non è necessario aggiungere nulla a questa classe, ma parte del codice che si aggiungerà altrove vi farà riferimento.

Per altre informazioni su come viene costruito l'esempio, vedere la panoramica della struttura dell'app.

Parte 2: Aggiungere DataGrid

Prima di iniziare a operare sui dati dei clienti, è necessario aggiungere un controllo dell'interfaccia utente per visualizzare i clienti. A tale scopo, verrà usato un controllo RadDataGrid di terze parti predefinito. Il pacchetto Telerik.UI.for.UniversalWindowsPlatform NuGet è già stato incluso in questo progetto. Aggiungiamo la griglia al nostro progetto.

  1. Apri Views\CustomerListPage.xaml da Esplora soluzioni. Aggiungi la riga di codice seguente all'interno del tag Page per dichiarare un mapping allo spazio dei nomi Telerik contenente la griglia dati.

        xmlns:telerikGrid="using:Telerik.UI.Xaml.Controls.Grid"
    
  2. Sotto CommandBar all'interno del RelativoPanel principale della visualizzazione, aggiungi un controllo RadDataGrid con alcune opzioni di configurazione di base:

    <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. È stata aggiunta la griglia dei dati, ma sono necessari dati da visualizzare. Aggiungi a questo le righe di codice seguenti:

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

    Ora che è stata definita un'origine di dati da visualizzare, RadDataGrid gestirà la maggior parte della logica dell'interfaccia utente. Tuttavia, se si esegue il progetto, non verranno comunque visualizzati dati. Questo perché ViewModel non lo sta ancora caricando.

App vuota, senza clienti

Parte 3: Lettura dei clienti

Quando viene inizializzato, ViewModels\CustomerListPageViewModel.cs chiama il metodo GetCustomerListAsync. Questo metodo deve recuperare i dati del cliente di test dal database SQLite incluso nell'esercitazione.

  1. In ViewModels\CustomerListPageViewModel.cs, aggiorna il metodo GetCustomerListAsync con questo codice:

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

    Il metodo GetCustomerListAsync viene chiamato quando ViewModel viene caricato, ma prima di questo passaggio non ha eseguito alcuna operazione. Qui abbiamo aggiunto una chiamata al metodo GetAsync in Repository/SqlCustomerRepository. In questo modo è possibile contattare il repository per recuperare una raccolta enumerabile di oggetti Customer. Quindi li analizza in singoli oggetti, prima di aggiungerli al relativo ObservableCollection interno in modo che possano essere visualizzati e modificati.

  2. Esegui l'app: sarà ora possibile vedere la griglia dei dati che visualizza l'elenco dei clienti.

Elenco iniziale di clienti

Parte 4: Modificare i clienti

Puoi modificare le voci nella griglia dei dati facendo doppio clic su di esse, ma è necessario assicurarsi che tutte le modifiche apportate nell'interfaccia utente vengano apportate anche alla raccolta di clienti nel code-behind. Ciò significa che è necessario implementare il data binding bidirezionale. Per altre informazioni su questo argomento, consulta introduzione al data binding.

  1. Prima di tutto, dichiara che ViewModels\CustomerListPageViewModel.cs implementa l'interfaccia INotifyPropertyChanged:

    public class CustomerListPageViewModel : INotifyPropertyChanged
    
  2. Quindi, all'interno del corpo principale della classe, aggiungi l'evento e il metodo seguenti:

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

    Il metodo OnPropertyChanged consente ai setter di generare facilmente l'evento PropertyChanged, necessario per il data binding bidirezionale.

  3. Aggiorna il setter per SelectedCustomer con questa chiamata di funzione:

    public CustomerViewModel SelectedCustomer
    {
        get => _selectedCustomer;
        set
        {
            if (_selectedCustomer != value)
            {
                _selectedCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  4. In Views\CustomerListPage.xaml, aggiungi la proprietà SelectedCustomer alla griglia dati.

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

    Questo associa la selezione dell'utente nella griglia dei dati all'oggetto Customer corrispondente nel code-behind. La modalità di associazione TwoWay consente di riflettere le modifiche apportate nell'interfaccia utente su tale oggetto.

  5. Eseguire l'app. Puoi ora vedere i clienti visualizzati nella griglia e apportare modifiche ai dati sottostanti tramite l'interfaccia utente.

Modifica di un cliente nella griglia dei dati

Parte 5: Aggiornare i clienti

Ora che è possibile visualizzare e modificare i clienti, è necessario essere in grado di eseguire il push delle modifiche al database e di eseguire il pull di eventuali aggiornamenti apportati da altri utenti.

  1. Torna a ViewModels\CustomerListPageViewModel.cs e passa al metodo UpdateCustomersAsync. Aggiornalo con questo codice per eseguire il push delle modifiche al database e recuperare le nuove informazioni:

    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();
    }
    

    Questo codice usa la proprietà IsModified di ViewModels\CustomerViewModel.cs, che viene aggiornata automaticamente ogni volta che il cliente viene modificato. Ciò consente di evitare chiamate non necessarie e di eseguire il push solo delle modifiche relative ai clienti aggiornati al database.

Parte 6: Creazione di un nuovo cliente

L'aggiunta di un nuovo cliente presenta un ostacolo, perché il cliente verrà visualizzato come riga vuota se lo si aggiunge all'interfaccia utente prima di fornire i valori per le relative proprietà. Non si tratta di un problema, ma in questo caso sarà più semplice impostare i valori iniziali di un cliente. In questa esercitazione verrà aggiunto un semplice pannello comprimibile, ma se si dispone di altre informazioni da aggiungere, è possibile creare una pagina separata a tale scopo.

Aggiornare il code-behind

  1. Aggiungi un nuovo campo privato e una nuova proprietà pubblica a ViewModels\CustomerListPageViewModel.cs. Verrà usato per controllare se il pannello è visibile o no.

    private bool _addingNewCustomer = false;
    
    public bool AddingNewCustomer
    {
        get => _addingNewCustomer;
        set
        {
            if (_addingNewCustomer != value)
            {
                _addingNewCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  2. Aggiungi una nuova proprietà pubblica a ViewModel, una relazione inversa del valore di AddingNewCustomer. Verrà usata per disabilitare i normali pulsanti della barra dei comandi quando il pannello è visibile.

    public bool EnableCommandBar => !AddingNewCustomer;
    

    È ora necessario un modo per visualizzare il pannello comprimibile e creare un cliente da modificare al suo interno.

  3. Aggiungi una nuova proprietà privata e pubblica a ViewModel per contenere il cliente appena creato.

    private CustomerViewModel _newCustomer;
    
    public CustomerViewModel NewCustomer
    {
        get => _newCustomer;
        set
        {
            if (_newCustomer != value)
            {
                _newCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  4. Aggiorna il metodo CreateNewCustomerAsync per creare un nuovo cliente, aggiungerlo al repository e impostarlo come cliente selezionato:

    public async Task CreateNewCustomerAsync()
    {
        CustomerViewModel newCustomer = new CustomerViewModel(new Models.Customer());
        NewCustomer = newCustomer;
        await App.Repository.Customers.UpsertAsync(NewCustomer.Model);
        AddingNewCustomer = true;
    }
    
  5. Aggiorna il metodo SaveInitialChangesAsync per aggiungere un cliente appena creato al repository, aggiornare l'interfaccia utente e chiudere il pannello.

    public async Task SaveInitialChangesAsync()
    {
        await App.Repository.Customers.UpsertAsync(NewCustomer.Model);
        await UpdateCustomersAsync();
        AddingNewCustomer = false;
    }
    
  6. Aggiungi la riga di codice seguente come riga finale nel setter per AddingNewCustomer:

    OnPropertyChanged(nameof(EnableCommandBar));
    

    In questo modo si garantisce che EnableCommandBar venga aggiornato automaticamente ogni volta che AddingNewCustomer viene modificato.

Aggiornare l'interfaccia utente

  1. Torna a Views\CustomerListPage.xaml e aggiungi StackPanel con le proprietà seguenti tra CommandBar e la griglia dati:

    <StackPanel
        x:Name="newCustomerPanel"
        Orientation="Horizontal"
        x:Load="{x:Bind ViewModel.AddingNewCustomer, Mode=OneWay}"
        RelativePanel.Below="mainCommandBar">
    </StackPanel>
    

    L'attributo x:Load garantisce che questo pannello venga visualizzato solo quando si aggiunge un nuovo cliente.

  2. Apporta la modifica seguente alla posizione della griglia dei dati per assicurarti che si muova verso il basso quando viene visualizzato il nuovo pannello:

    RelativePanel.Below="newCustomerPanel"
    
  3. Aggiorna il pannello Stack con quattro controlli TextBox. Verranno associati alle singole proprietà del nuovo cliente e consentiranno di modificarne i valori prima di aggiungerli alla griglia dei dati.

    <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. Aggiungi un pulsante semplice al nuovo pannello Stack per salvare il cliente appena creato:

    <StackPanel>
        <!--Text boxes from step 3-->
        <AppBarButton
            x:Name="SaveNewCustomer"
            Click="{x:Bind ViewModel.SaveInitialChangesAsync}"
            Icon="Save"/>
    </StackPanel>
    
  5. Aggiorna CommandBar, in modo che i normali pulsanti di creazione, eliminazione e aggiornamento siano disabilitati quando il pannello Stack è visibile:

    <CommandBar
        x:Name="mainCommandBar"
        HorizontalAlignment="Stretch"
        IsEnabled="{x:Bind ViewModel.EnableCommandBar, Mode=OneWay}"
        Background="AliceBlue">
        <!--App bar buttons-->
    </CommandBar>
    
  6. Eseguire l'app. È ora possibile creare un cliente e immetterne i dati nel pannello Stack.

Creazione di un nuovo cliente

Parte 7: Eliminare un cliente

L'eliminazione di un cliente è l'operazione di base finale che è necessario implementare. Quando si elimina un cliente selezionato all'interno della griglia dei dati, è necessario chiamare immediatamente UpdateCustomersAsync per aggiornare l'interfaccia utente. Tuttavia, non è necessario chiamare tale metodo se si elimina un cliente appena creato.

  1. Passa a ViewModels\CustomerListPageViewModel.cs e aggiorna il metodo DeleteAndUpdateAsync:

    public async void DeleteAndUpdateAsync()
    {
        if (SelectedCustomer != null)
        {
            await App.Repository.Customers.DeleteAsync(_selectedCustomer.Model.Id);
        }
        await UpdateCustomersAsync();
    }
    
  2. In Views\CustomerListPage.xaml, aggiorna il pannello Stack per aggiungere un nuovo cliente in modo che contenga un secondo pulsante:

    <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. In ViewModels\CustomerListPageViewModel.cs, aggiorna il metodo DeleteNewCustomerAsync per eliminare il nuovo cliente:

    public async Task DeleteNewCustomerAsync()
    {
        if (NewCustomer != null)
        {
            await App.Repository.Customers.DeleteAsync(_newCustomer.Model.Id);
            AddingNewCustomer = false;
        }
    }
    
  4. Eseguire l'app. È ora possibile eliminare i clienti, all'interno della griglia dei dati o nel pannello Stack.

Eliminazione di un nuovo cliente

Conclusione

Complimenti. A questo scopo, l'app dispone ora di un'ampia gamma di operazioni di database locali. Puoi creare, leggere, aggiornare ed eliminare i clienti all'interno dell'interfaccia utente e queste modifiche verranno salvate nel database e verranno mantenute nei successivi avvii dell'app.

Al termine, prendi in considerazione quanto segue:

Oppure, se sei in grado di affrontare una sfida, puoi continuare...

Approfondimenti: connessione a un database remoto

È stata fornita una procedura dettagliata su come implementare queste chiamate su un database SQLite locale. Ma cosa succede se si vuole usare un database remoto?

Se desideri provare, è necessario un account Azure Active Directory (AAD) personalizzato e la possibilità di ospitare la propria origine dati.

È necessario aggiungere l'autenticazione, le funzioni per gestire le chiamate REST e quindi creare un database remoto con cui interagire. Il codice è contenuto nell'esempio completo del database degli ordini cliente a cui è possibile fare riferimento per ogni operazione necessaria.

Impostazioni e configurazione

I passaggi necessari per connettersi al database remoto sono descritti nel file leggimi dell'esempio. Sarà necessario eseguire le operazioni seguenti:

Autenticazione

È necessario creare un pulsante per avviare una sequenza di autenticazione e un popup o una pagina separata per raccogliere le informazioni relative a un utente. Dopo aver eseguito questa operazione, è necessario fornire il codice che richiede le informazioni di un utente e le utilizza per acquisire un token di accesso. L'esempio di database per gli ordini dei clienti esegue il wrapping delle chiamate di Microsoft Graph con la libreria WebAccountManager per acquisire un token e gestire l'autenticazione in un account AAD.

Chiamate REST

Non è necessario modificare alcun codice aggiunto in questa esercitazione per implementare le chiamate REST. È invece necessario eseguire quanto segue:

  • Crea nuove implementazioni delle interfacce ICustomerRepository e ITutorialRepository, implementando lo stesso set di funzioni tramite REST anziché SQLite. È necessario serializzare e deserializzare JSON ed eseguire il wrapping delle chiamate REST in una classe HttpHelper separata, se necessario. Per informazioni specifiche, consulta l'esempio completo.
  • In App.xaml.cs, crea una nuova funzione per inizializzare il repository REST e chiamala al posto di SqliteDatabase quando l'app viene inizializzata. Anche in questo caso, fai riferimento all'esempio completo.

Dopo aver completato tutti e tre questi passaggi, dovresti essere in grado di eseguire l'autenticazione all'account AAD tramite l'app. Le chiamate REST al database remoto sostituiranno le chiamate SQLite locali, ma l'esperienza utente dovrebbe essere la stessa. Se ti senti ancora più ambizioso, puoi aggiungere una pagina di impostazioni, per consentire all'utente di passare dinamicamente da uno all'altro.