2 - Pasos para crear una aplicación universal de Windows.


El Visual Studio 2019 nos ayuda para crear un esqueleto básico para implementar una aplicación universal de Windows.

Debemos una vez arrancado el Visual Studio elegir la opción Archivo -> Nuevo -> Proyecto...

entorno del visual Studio 2019

Aparece un diálogo donde debemos seleccionar la plantilla "Aplicación vacía (Windows universal)":

entorno del visual Studio 2019

Y un segundo diálogo donde debemos definir el nombre del proyecto y el directorio donde se almacenará:

entorno del visual Studio 2019

También se nos pide que seleccionemos la versión destino de "Windows 10" y la versión mínima que debe tener el equipo donde se ejecutará la aplicación:

entorno del visual Studio 2019

Una vez que aceptamos los datos cargados en el diálogo el Visual Studio se encarga de crear todas las carpetas y archivos básicos para disponer de una "Aplicación Universal de Windows"

En el explorador de soluciones podemos observar todos las carpetas y archivos que se han creador:

entorno del visual Studio 2019 aplicación universal de windows

A lo largo de este tutorial iremos viendo cual es el objetivo de cada uno de estos archivos y como se relacionan entre sí.

Archivos MainPage.xaml y MainPage.xaml.cs

El archivo MainPage.xaml es nuestra primer página o interfaz visual de la aplicación. Se utiliza el lenguaje de marcado xaml para definir los controles visuales (si no conoce nada de xaml puede leer la siguiente documentación.)

Podemos seleccionar el archivo MainPage.xaml y ver su contenido como xaml en la parte inferior y en forma visual en la parte superior:

MainPage.xaml

Como veremos más adelante muchas veces escribiremos las marcas xaml directamente en el editor de texto pero en algunas situaciones arrastraremos controles visuales directamente en la interfaz visual de la parte superior (esto hará que se genere automáticamente el código xaml en la parte inferior)

Probemos de arrastrar un objeto de la clase Button del "Cuadro de herramientas" a la interfaz visual de nuestra aplicación:

MainPage.xaml Button

Como podemos observar cuando arrastramos el objeto Button sobre el formulario se agrega automáticamente la marca "Button" dentro del archivo "MainPage.xaml".

Si lo desplazamos al botón dentro del formulario veremos que la propiedad Margin de la marca Button se modifica.

Los valores de las propiedades del objeto Button se pueden modificar directamente desde el archivo "MainPage.xaml" como desde la ventana de propiedades:

MainPage.xaml Button Content

Si tenemos seleccionado el objeto Button en la interfaz visual desde la ventana de propiedades podemos acceder a la propiedad "Content" que almacena el texto del botón. Este mismo cambio lo podemos hacer desde el editor de texto accediendo al archivo xaml y modificando directamente la propiedad "Content" del objeto "Button":

<Page
    x:Class="Proyecto1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Proyecto1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <Button Content="Opción 1" Margin="51,60,0,0" VerticalAlignment="Top"/>

    </Grid>
</Page>

También definiremos un nombre de objeto para nuestro "button", seleccionamos el botón y definimos en la ventana de "propiedades" el nombre "boton1":

MainPage.xaml Button Name

Por otro lado debemos definir los eventos a que responden nuestros elementos visuales. Seleccionemos el botón y desde la ventana de "Propiedades" elegimos el ícono de eventos:

MainPage.xaml Button event

Hacemos doble clic con el mouse en el evento "Click" y se nos abre el archivo "MainPage.xaml.cs" que contendrá todo el código a implementar para los distintos eventos:

MainPage.xaml Button event

El método Boton1_Click se ejecutará cuando sea presionado el botón por el usuario de nuestra aplicación:

        private void Boton1_Click(object sender, RoutedEventArgs e)
        {

        }

Si abrimos el archivo MainPage.xaml veremos que se ha agregado una propiedad (Click) a dicho objeto que lo relaciona con el evento que acabamos de definir:

        <Button x:Name="boton1" Content="Opción 1" Margin="51,60,0,0" VerticalAlignment="Top" Click="Boton1_Click" />

Vamos a codificar en el archivo MainPage.xaml.cs el siguiente código para cuando sea presionado el botón:

        private void Boton1_Click(object sender, RoutedEventArgs e)
        {
            boton1.Content = "Se presionó el botón";
        }

Es decir que al ser presionado el botón por el usuario cambiará su contenido con una nueva cadena de caracteres.

Ejecución del programa.

Podemos iniciar nuestra aplicación de varias maneras:

Al ejecutarse la aplicación podemos ver que aparece el formulario en pantalla con una interfaz similar a esta:

ejecución aplicación universal de windows

Lo único extraño que podemos ver es un recuadro negro con unos íconos. Se trata de herramientas de depuración.

Los datos de depuración no se verán cuando desarrollemos la aplicación definitiva a distribuir.

Volviendo a nuestra aplicación al presionar el botón podemos observar que se dispara el evento Boton1_Click donde se cambia el contenido del botón:

ejecución aplicación universal de windows evento

Vemos que cambió el texto de "Opción 1" a "Se presionó el botón".

Ejecución del programa en otros emuladores

Podemos desde el ícono de ejecución seleccionar otro tipo de emulador:

emuladores de aplicaciones universales de Windows

Ahora podemos ejecutar nuevamente nuestra aplicación con el emulador seleccionado:

emuladores de aplicaciones universales de Windows

Como ha visto la carga de emulador lleva bastante tiempo hasta que se inicia. Luego de iniciar el emulador no lo cierre, sino cambie a la ventana del Visual Studio, seleccione "Detener depuración":

detener depuracion aplicaciones universales de Windows

y realice los cambios del programa y vuelva a iniciar la aplicación (como verá ahora el emulador está ya en ejecución y solo se tardará muy poco tiempo hasta que se inicie nuestro programa)

Otros archivos que contiene una aplicación universal de windows

Los archivos App.xaml y App.xaml.cs son el punto de entrada principal de una aplicación universal de Windows. En el archivo xaml se definen estilos y recursos que podrán ser utilizados en todos los formularios de la aplicación. En el archivo App.xaml.cs se codifican los eventos principales del ciclo de vida de una aplicación: OnLaunched, OnSuspending etc.

El archivo App.xaml (en nuestra aplicación mínimo no hemos modificada este archivo):

<Application
    x:Class="Proyecto1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Proyecto1">

</Application>

El archivo App.xaml.cs (en nuestra aplicación mínimo no hemos modificada este archivo):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace Proyecto1
{
    /// <summary>
    /// Proporciona un comportamiento específico de la aplicación para complementar la clase Application predeterminada.
    /// </summary>
    sealed partial class App : Application
    {
        /// <summary>
        /// Inicializa el objeto de aplicación Singleton. Esta es la primera línea de código creado
        /// ejecutado y, como tal, es el equivalente lógico de main() o WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Se invoca cuando la aplicación la inicia normalmente el usuario final. Se usarán otros puntos
        /// de entrada cuando la aplicación se inicie para abrir un archivo específico, por ejemplo.
        /// </summary>
        /// <param name="e">Información detallada acerca de la solicitud y el proceso de inicio.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // No repetir la inicialización de la aplicación si la ventana tiene contenido todavía,
            // solo asegurarse de que la ventana está activa.
            if (rootFrame == null)
            {
                // Crear un marco para que actúe como contexto de navegación y navegar a la primera página.
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Cargar el estado de la aplicación suspendida previamente
                }

                // Poner el marco en la ventana actual.
                Window.Current.Content = rootFrame;
            }

            if (e.PrelaunchActivated == false)
            {
                if (rootFrame.Content == null)
                {
                    // Cuando no se restaura la pila de navegación, navegar a la primera página,
                    // configurando la nueva página pasándole la información requerida como
                    //parámetro de navegación
                    rootFrame.Navigate(typeof(MainPage), e.Arguments);
                }
                // Asegurarse de que la ventana actual está activa.
                Window.Current.Activate();
            }
        }

        /// <summary>
        /// Se invoca cuando la aplicación la inicia normalmente el usuario final. Se usarán otros puntos
        /// </summary>
        /// <param name="sender">Marco que produjo el error de navegación</param>
        /// <param name="e">Detalles sobre el error de navegación</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        /// <summary>
        /// Se invoca al suspender la ejecución de la aplicación. El estado de la aplicación se guarda
        /// sin saber si la aplicación se terminará o se reanudará con el contenido
        /// de la memoria aún intacto.
        /// </summary>
        /// <param name="sender">Origen de la solicitud de suspensión.</param>
        /// <param name="e">Detalles sobre la solicitud de suspensión.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Guardar el estado de la aplicación y detener toda actividad en segundo plano
            deferral.Complete();
        }
    }
}

Otro archivo por defecto que se crea cuando desarrollamos una aplicación universal es Package.appxmanifest. En este archivo se definen entre otras cosas el nombre de la aplicación, el idioma, las rotaciones del dispositivo permitidas, las imágenes de los íconos a mostrar en la tienda de aplicaciones de Microsoft, los dispositivos con los que se puede conectar y recursos que puede acceder (micrófono, cámara, GPS etc), número de versión de nuestra aplicación etc.

Cuando seleccionamos este archivo desde el "Explorador de soluciones" nos muestra una serie de diálogos para configurar estos parámetros (a medida que avancemos en el tutorial iremos probando diferentes configuraciones):

Package.appxmanifest

Se crea también una carpeta llamada Assets donde dispondremos todos los recursos que requerirá nuestra aplicación: imágenes, archivos de sonido, videos etc.

Por defecto incorpora solo 7 imágenes:

Assets

Este proyecto lo puede descargar en un zip desde este enlace :Proyecto1.zip

Retornar