Tutorial: Crear una aplicación de base de datos de clientes

En este tutorial se crea una aplicación sencilla para administrar una lista de clientes. Al hacerlo, presenta una selección de conceptos básicos para aplicaciones empresariales en UWP. Aprenderá a:

  • Implemente las operaciones Create, Read, Update y Delete en una base de datos SQL local.
  • Agregue una cuadrícula de datos para mostrar y editar los datos de los clientes en la interfaz de usuario.
  • Organice los elementos de la interfaz de usuario juntos en un diseño de formulario básico.

El punto de partida de este tutorial es una aplicación de página única con una interfaz de usuario mínima y funcionalidad, basada en una versión simplificada de la aplicación de ejemplo Base de datos de pedidos de clientes. Está escrito en C# y XAML, y esperamos que tengas una familiaridad básica con ambos lenguajes.

Página principal de la aplicación de trabajo

Requisitos previos

Después de clonar o descargar el repositorio, puede editar el proyecto abriendo CustomerDatabaseTutorial.sln con Visual Studio.

Nota

Este tutorial se basa en el ejemplo de base de datos de pedidos de clientes que se ha actualizado recientemente para hacer uso de WinUI y la SDK de Aplicaciones para Windows. Hasta que se actualice este tutorial y el código, habrá diferencias entre los dos ejemplos.

Parte 1: Código de interés

Si ejecutas la aplicación inmediatamente después de abrirla, verás algunos botones en la parte superior de una pantalla en blanco. Aunque no es visible para usted, la aplicación ya incluye una base de datos sqLite local aprovisionada con algunos clientes de prueba. Desde aquí, empezará implementando un control de interfaz de usuario para mostrar a esos clientes y, a continuación, pasar a agregar operaciones en la base de datos. Antes de empezar, aquí es donde trabajará.

Vistas

CustomerListPage.xaml es la vista de la aplicación, que define la interfaz de usuario de la página única de este tutorial. Cada vez que necesite agregar o cambiar un elemento visual en la interfaz de usuario, lo hará en este archivo. Este tutorial le guiará a través de la adición de estos elementos:

  • RadDataGrid para mostrar y editar los clientes.
  • StackPanel para establecer los valores iniciales de un nuevo cliente.

ViewModels

ViewModels\CustomerListPageViewModel.cs es donde se encuentra la lógica fundamental de la aplicación. Todas las acciones del usuario realizadas en la vista se pasarán a este archivo para su procesamiento. En este tutorial, agregará código nuevo e implementará los métodos siguientes:

  • CreateNewCustomerAsync, que inicializa un nuevo objeto CustomerViewModel.
  • DeleteNewCustomerAsync, que quita un nuevo cliente antes de que se muestre en la interfaz de usuario.
  • DeleteAndUpdateAsync, que controla la lógica del botón eliminar.
  • GetCustomerListAsync, que recupera una lista de clientes de la base de datos.
  • SaveInitialChangesAsync, que agrega la información de un nuevo cliente a la base de datos.
  • UpdateCustomersAsync, que actualiza la interfaz de usuario para reflejar los clientes agregados o eliminados.

CustomerViewModel es un contenedor para la información de un cliente, que realiza un seguimiento de si se ha modificado recientemente o no. No tendrá que agregar nada a esta clase, pero parte del código que agregará en otro lugar hará referencia a ella.

Para obtener más información sobre cómo se construye el ejemplo, consulte la información general sobre la estructura de la aplicación.

Parte 2: Agregar DataGrid

Antes de empezar a operar en los datos de los clientes, deberá agregar un control de interfaz de usuario para mostrar esos clientes. Para ello, usaremos un control RadDataGrid de terceros creado previamente. El paquete NuGet Telerik.UI.for.UniversalWindowsPlatform ya se ha incluido en este proyecto. Vamos a agregar la cuadrícula al proyecto.

  1. Abra Views\CustomerListPage.xaml desde el Explorador de soluciones. Agregue la siguiente línea de código dentro de la etiqueta Page para declarar una asignación al espacio de nombres telerik que contiene la cuadrícula de datos.

        xmlns:telerikGrid="using:Telerik.UI.Xaml.Controls.Grid"
    
  2. Debajo de commandBar dentro del elemento RelativePanel principal de la vista, agregue un control RadDataGrid , con algunas opciones de configuración básicas:

     <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. Ha agregado la cuadrícula de datos, pero necesita datos para mostrar. Agregue las siguientes líneas de código:

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

    Ahora que ha definido un origen de datos para mostrar, RadDataGrid controlará la mayor parte de la lógica de la interfaz de usuario. Sin embargo, si ejecuta el proyecto, todavía no verá ningún dato en pantalla. Esto se debe a que ViewModel aún no lo está cargando.

Aplicación en blanco, sin clientes

Parte 3: Leer clientes

Cuando se inicializa, ViewModels\CustomerListPageViewModel.cs llama al método GetCustomerListAsync . Ese método debe recuperar los datos del cliente de prueba de la base de datos de SQLite que se incluye en el tutorial.

  1. En ViewModels\CustomerListPageViewModel.cs, actualice el método GetCustomerListAsync con este código:

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

    Se llama al método GetCustomerListAsync cuando se carga ViewModel, pero antes de este paso, no hizo nada. Aquí hemos agregado una llamada al método GetAsync en Repository/SqlCustomerRepository. Esto le permite ponerse en contacto con el repositorio para recuperar una colección enumerable de objetos Customer. A continuación, los analiza en objetos individuales, antes de agregarlos a su ObservableCollection interno para que se puedan mostrar y editar.

  2. Ejecutar la aplicación: ahora verá la cuadrícula de datos que muestra la lista de clientes.

Lista inicial de clientes

Parte 4: Editar clientes

Puede editar las entradas de la cuadrícula de datos haciendo doble clic en ellas, pero debe asegurarse de que los cambios que realice en la interfaz de usuario también se realicen en la colección de clientes en el código subyacente. Esto significa que tendrá que implementar el enlace de datos bidireccional. Si desea obtener más información sobre esto, consulte nuestra introducción al enlace de datos.

  1. En primer lugar, declare que ViewModels\CustomerListPageViewModel.cs implementa la interfaz INotifyPropertyChanged :

    public class CustomerListPageViewModel : INotifyPropertyChanged
    
  2. A continuación, en el cuerpo principal de la clase , agregue el siguiente evento y método:

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

    El método OnPropertyChanged facilita que los establecedores generen el evento PropertyChanged , que es necesario para el enlace de datos bidireccional.

  3. Actualice el establecedor de SelectedCustomer con esta llamada de función:

    public CustomerViewModel SelectedCustomer
    {
         get => _selectedCustomer;
         set
         {
            if (_selectedCustomer != value)
            {
                 _selectedCustomer = value;
                 OnPropertyChanged();
            }
         }
    }
    
  4. En Views\CustomerListPage.xaml, agregue la propiedad SelectedCustomer a la cuadrícula de datos.

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

    Esto asocia la selección del usuario en la cuadrícula de datos con el objeto Customer correspondiente en el código subyacente. El modo de enlace TwoWay permite que los cambios realizados en la interfaz de usuario se reflejen en ese objeto.

  5. Ejecute la aplicación. Ahora puede ver los clientes mostrados en la cuadrícula y realizar cambios en los datos subyacentes a través de la interfaz de usuario.

Edición de un cliente en la cuadrícula de datos

Parte 5: Actualizar clientes

Ahora que puede ver y editar los clientes, deberá poder insertar los cambios en la base de datos y extraer las actualizaciones realizadas por otros usuarios.

  1. Vuelva a ViewModels\CustomerListPageViewModel.cs y vaya al método UpdateCustomersAsync . Actualícelo con este código para insertar cambios en la base de datos y recuperar cualquier nueva información:

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

    Este código utiliza la propiedad IsModified de ViewModels\CustomerViewModel.cs, que se actualiza automáticamente cada vez que se cambia el cliente. Esto le permite evitar llamadas innecesarias y solo insertar cambios de clientes actualizados en la base de datos.

Parte 6: Crear un nuevo cliente

Agregar un nuevo cliente presenta un desafío, ya que el cliente aparecerá como una fila en blanco si la agrega a la interfaz de usuario antes de proporcionar valores para sus propiedades. Esto no es un problema, pero aquí vamos a facilitar la configuración de los valores iniciales de un cliente. En este tutorial, agregaremos un panel contraíble sencillo, pero si tuviera más información para agregar podría crear una página independiente para este propósito.

Actualización del código subyacente

  1. Agregue un nuevo campo privado y una propiedad pública a ViewModels\CustomerListPageViewModel.cs. Se usará para controlar si el panel está visible o no.

    private bool _addingNewCustomer = false;
    
    public bool AddingNewCustomer
    {
         get => _addingNewCustomer;
         set
         {
            if (_addingNewCustomer != value)
            {
                 _addingNewCustomer = value;
                 OnPropertyChanged();
            }
         }
    }
    
  2. Agregue una nueva propiedad pública a ViewModel, un inverso del valor de AddingNewCustomer. Se usará para deshabilitar los botones de la barra de comandos normales cuando el panel esté visible.

    public bool EnableCommandBar => !AddingNewCustomer;
    

    Ahora necesitará una manera de mostrar el panel contraíble y crear un cliente para editarlo.

  3. Agregue una nueva propiedad pública y fiend privada a ViewModel para contener el cliente recién creado.

    private CustomerViewModel _newCustomer;
    
    public CustomerViewModel NewCustomer
    {
        get => _newCustomer;
        set
        {
            if (_newCustomer != value)
            {
                _newCustomer = value;
                OnPropertyChanged();
            }
        }
    }
    
  4. Actualice el método CreateNewCustomerAsync para crear un nuevo cliente, agregarlo al repositorio y establecerlo como el cliente seleccionado:

    public async Task CreateNewCustomerAsync()
    {
        CustomerViewModel newCustomer = new CustomerViewModel(new Models.Customer());
        NewCustomer = newCustomer;
        await App.Repository.Customers.UpsertAsync(NewCustomer.Model);
        AddingNewCustomer = true;
    }
    
  5. Actualice el método SaveInitialChangesAsync para agregar un cliente recién creado al repositorio, actualizar la interfaz de usuario y cerrar el panel.

    public async Task SaveInitialChangesAsync()
    {
        await App.Repository.Customers.UpsertAsync(NewCustomer.Model);
        await UpdateCustomersAsync();
        AddingNewCustomer = false;
    }
    
  6. Agregue la siguiente línea de código como línea final en el establecedor para AddingNewCustomer:

    OnPropertyChanged(nameof(EnableCommandBar));
    

    Esto garantizará que EnableCommandBar se actualice automáticamente cada vez que se cambie AddingNewCustomer .

Actualización de la interfaz de usuario

  1. Vuelva a Views\CustomerListPage.xaml y agregue un StackPanel con las siguientes propiedades entre commandBar y la cuadrícula de datos:

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

    El atributo x:Load garantiza que este panel solo aparece cuando se agrega un nuevo cliente.

  2. Realice el siguiente cambio en la posición de la cuadrícula de datos para asegurarse de que se mueve hacia abajo cuando aparezca el nuevo panel:

    RelativePanel.Below="newCustomerPanel"
    
  3. Actualice el panel de pila con cuatro controles TextBox . Se enlazarán a las propiedades individuales del nuevo cliente y le permitirán editar sus valores antes de agregarlos a la cuadrícula de datos.

    <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. Agregue un botón sencillo al nuevo panel de pila para guardar el cliente recién creado:

    <StackPanel>
        <!--Text boxes from step 3-->
        <AppBarButton
            x:Name="SaveNewCustomer"
            Click="{x:Bind ViewModel.SaveInitialChangesAsync}"
            Icon="Save"/>
    </StackPanel>
    
  5. Actualice la barra de comandos, por lo que los botones normales de creación, eliminación y actualización se deshabilitan cuando el panel de pila está visible:

    <CommandBar
        x:Name="mainCommandBar"
        HorizontalAlignment="Stretch"
        IsEnabled="{x:Bind ViewModel.EnableCommandBar, Mode=OneWay}"
        Background="AliceBlue">
        <!--App bar buttons-->
    </CommandBar>
    
  6. Ejecute la aplicación. Ahora puede crear un cliente y escribir sus datos en el panel de pila.

Creación de un nuevo cliente

Parte 7: Eliminar un cliente

La eliminación de un cliente es la operación básica final que debe implementar. Al eliminar un cliente seleccionado en la cuadrícula de datos, querrá llamar inmediatamente a UpdateCustomersAsync para actualizar la interfaz de usuario. Sin embargo, no es necesario llamar a ese método si elimina un cliente que acaba de crear.

  1. Vaya a ViewModels\CustomerListPageViewModel.cs y actualice el método DeleteAndUpdateAsync :

    public async void DeleteAndUpdateAsync()
    {
        if (SelectedCustomer != null)
        {
            await App.Repository.Customers.DeleteAsync(_selectedCustomer.Model.Id);
        }
        await UpdateCustomersAsync();
    }
    
  2. En Views\CustomerListPage.xaml, actualice el panel de pila para agregar un nuevo cliente para que contenga un segundo botón:

     <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. En ViewModels\CustomerListPageViewModel.cs, actualice el método DeleteNewCustomerAsync para eliminar el nuevo cliente:

    public async Task DeleteNewCustomerAsync()
    {
        if (NewCustomer != null)
        {
            await App.Repository.Customers.DeleteAsync(_newCustomer.Model.Id);
            AddingNewCustomer = false;
        }
    }
    
  4. Ejecute la aplicación. Ahora puede eliminar clientes, ya sea dentro de la cuadrícula de datos o en el panel de pila.

Eliminar un nuevo cliente

Conclusión

Enhorabuena. Con todo esto, la aplicación ahora tiene una gama completa de operaciones de base de datos locales. Puede crear, leer, actualizar y eliminar clientes dentro de la interfaz de usuario, y estos cambios se guardan en la base de datos y se conservarán en diferentes inicios de la aplicación.

Ahora que ha terminado, tenga en cuenta lo siguiente:

O si está buscando un desafío, puede continuar en adelante...

Ir más allá: Conexión a una base de datos remota

Hemos proporcionado un tutorial paso a paso sobre cómo implementar estas llamadas en una base de datos de SQLite local. Pero, ¿qué ocurre si desea usar una base de datos remota, en su lugar?

Si quiere probar esto, necesitará su propia cuenta de Azure Active Directory (AAD) y la capacidad de hospedar su propio origen de datos.

Deberá agregar autenticación, funciones para controlar las llamadas REST y, a continuación, crear una base de datos remota con la que interactuar. Hay código en el ejemplo completo de base de datos de pedidos de clientes que puede hacer referencia para cada operación necesaria.

Valores y configuración

Los pasos necesarios para conectarse a su propia base de datos remota se detallan en el archivo Léame del ejemplo. Deberá hacer lo siguiente:

  • Proporcione el identificador de cliente de la cuenta de Azure a Constants.cs.
  • Proporcione la dirección URL de la base de datos remota a Constants.cs.
  • Proporcione la cadena de conexión de la base de datos a Constants.cs.
  • Asocie la aplicación a Microsoft Store.
  • Copie el proyecto de servicio en la aplicación e impleméntelo en Azure.

Authentication

Deberá crear un botón para iniciar una secuencia de autenticación y un elemento emergente o una página independiente para recopilar la información de un usuario. Una vez que lo haya creado, deberá proporcionar código que solicite la información de un usuario y lo use para adquirir un token de acceso. El ejemplo de base de datos de pedidos de clientes encapsula las llamadas de Microsoft Graph con la biblioteca WebAccountManager para adquirir un token y controlar la autenticación en una cuenta de AAD.

Llamadas de REST

No tendrá que modificar ninguno de los códigos que hemos agregado en este tutorial para implementar llamadas REST. En su lugar, deberá hacer lo siguiente:

  • Cree nuevas implementaciones de las interfaces ICustomerRepository e ITutorialRepository , implementando el mismo conjunto de funciones a través de REST en lugar de SQLite. Tendrá que serializar y deserializar JSON, y puede encapsular las llamadas REST en una clase HttpHelper independiente si es necesario. Consulte el ejemplo completo para obtener información específica.
  • En App.xaml.cs, cree una nueva función para inicializar el repositorio REST y llámala en lugar de SqliteDatabase cuando se inicialice la aplicación. De nuevo, consulte el ejemplo completo.

Una vez completados los tres pasos, debería poder autenticarse en su cuenta de AAD a través de la aplicación. Las llamadas REST a la base de datos remota reemplazarán las llamadas locales de SQLite, pero la experiencia del usuario debe ser la misma. Si se siente aún más ambicioso, puede agregar una página de configuración para permitir al usuario cambiar dinámicamente entre los dos.