> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-9-la-construccion.-navegacion-y-configuracion-de-usuario/inicio-de-la-aplicacion.md).

# Inicio de la aplicación

El **inicio de la aplicación** es una fase crucial en el ciclo de vida de una aplicación UWP, ya que determina cómo se configuran y preparan los servicios necesarios para el correcto funcionamiento de la aplicación. En esta sección, abordaremos las **modificaciones realizadas en el servicio `AppointmentService`**, así como en otros servicios como `ProjectHelper`, y cómo se integran estos desde `App.xaml.cs` al iniciar la aplicación. Además, discutiremos cómo manejar la **apertura de la aplicación desde una cita o evento**, garantizando que la aplicación responda adecuadamente a estas interacciones externas.

## Modificaciones en los Servicios (`AppointmentService`, `ProjectHelper`, etc.)

Para asegurar que los servicios fundamentales estén disponibles desde el inicio de la aplicación, es necesario inicializarlos y configurarlos en el archivo `App.xaml.cs`. Esto garantiza que cualquier parte de la aplicación que dependa de estos servicios pueda acceder a ellos de manera consistente y eficiente.

### `AppointmentService`

El servicio `AppointmentService` se encarga de gestionar las citas y eventos dentro de la aplicación. Para integrarlo en el inicio de la aplicación, realizamos las siguientes modificaciones:

```csharp
// AppointmentService.cs
public class AppointmentService
{
    private readonly ICalendarProvider _calendarProvider;

    public AppointmentService(ICalendarProvider calendarProvider)
    {
        _calendarProvider = calendarProvider;
    }

    public async Task<IEnumerable<Appointment>> GetAppointmentsAsync(DateTime date)
    {
        // Lógica para obtener las citas del día especificado
        return await _calendarProvider.FetchAppointmentsAsync(date);
    }

    // Otros métodos relacionados con la gestión de citas
}
```

### `ProjectHelper`

El servicio `ProjectHelper` facilita operaciones comunes relacionadas con los proyectos, como obtener, actualizar o eliminar proyectos.

```csharp
// ProjectHelper.cs
public class ProjectHelper
{
    private readonly IProjectRepository _projectRepository;

    public ProjectHelper(IProjectRepository projectRepository)
    {
        _projectRepository = projectRepository;
    }

    public async Task<Project> GetProjectByIdAsync(int id)
    {
        return await _projectRepository.GetByIdAsync(id);
    }

    // Otros métodos auxiliares para gestionar proyectos
}
```

### Inicialización de Servicios en `App.xaml.cs`

Para utilizar estos servicios desde cualquier parte de la aplicación, los registramos en el contenedor de servicios durante el inicio de la aplicación.

```csharp
// App.xaml.cs
using Microsoft.Extensions.DependencyInjection;
using Windows.ApplicationModel.Activation;

sealed partial class App : Application
{
    public static IServiceProvider Services { get; private set; }

    public App()
    {
        this.InitializeComponent();
        this.Suspending += OnSuspending;
        ConfigureServices();
    }

    private void ConfigureServices()
    {
        var serviceCollection = new ServiceCollection();

        // Registro de proveedores
        serviceCollection.AddSingleton<ICalendarProvider, CalendarProvider>();
        serviceCollection.AddSingleton<IProjectRepository, ProjectRepository>();

        // Registro de servicios
        serviceCollection.AddSingleton<AppointmentService>();
        serviceCollection.AddSingleton<ProjectHelper>();

        // Registro de ViewModels y otros servicios según sea necesario
        // serviceCollection.AddTransient<MainViewModel>();
        // serviceCollection.AddTransient<SettingsViewModel>();
        // ...

        Services = serviceCollection.BuildServiceProvider();
    }

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;

        if (rootFrame == null)
        {
            rootFrame = new Frame();
            rootFrame.NavigationFailed += OnNavigationFailed;

            Window.Current.Content = rootFrame;
        }

        if (e.PrelaunchActivated == false)
        {
            if (rootFrame.Content == null)
            {
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            Window.Current.Activate();
        }

        // Manejo de apertura desde una cita/evento
        HandleActivation(e);
    }

    private void HandleActivation(IActivatedEventArgs args)
    {
        if (args.Kind == ActivationKind.Protocol)
        {
            var protocolArgs = args as ProtocolActivatedEventArgs;
            string uri = protocolArgs.Uri.ToString();

            // Parsear la URI para determinar la acción
            // Ejemplo de URI: myapp://appointment?id=123
            var uriScheme = new Uri(uri);
            if (uriScheme.Host.Equals("appointment", StringComparison.OrdinalIgnoreCase))
            {
                var queryParams = Microsoft.Toolkit.Uwp.Helpers.SystemNavigationHelper.ParseQueryString(uriScheme.Query);
                if (queryParams.ContainsKey("id") && int.TryParse(queryParams["id"], out int appointmentId))
                {
                    var frame = Window.Current.Content as Frame;
                    frame.Navigate(typeof(AppointmentDetailPage), appointmentId);
                }
            }
        }
    }

    private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
    {
        throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
    }

    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        // Guardar el estado de la aplicación
    }
}
```

**Explicación del Código:**

1. **Registro de Servicios:**
   * Utilizamos `Microsoft.Extensions.DependencyInjection` para registrar los servicios y sus dependencias.
   * `AppointmentService` y `ProjectHelper` se registran como **singleton**, asegurando que haya una única instancia durante el ciclo de vida de la aplicación.
   * Otros servicios y ViewModels se pueden registrar según sea necesario.
2. **Acceso a los Servicios:**
   * `App.Services` proporciona un punto de acceso global para los servicios registrados, permitiendo inyectarlos en los ViewModels u otras clases.
3. **Manejo de Activación desde una Cita/Eventos:**
   * El método `HandleActivation` detecta si la aplicación se ha lanzado desde un protocolo específico, como una cita o evento.
   * Se parsea la URI para extraer parámetros relevantes (por ejemplo, `id=123`) y se navega a la página de detalle correspondiente (`AppointmentDetailPage`) pasando el `appointmentId`.

## Apertura desde una Cita/Eventos

Manejar la apertura de la aplicación desde una cita o evento permite a los usuarios acceder directamente a información relevante sin tener que navegar manualmente a través de la aplicación. A continuación, se detalla cómo implementar esta funcionalidad.

### Paso 1: Definir el Protocolo de Activación

Primero, debemos definir un protocolo personalizado en el archivo `Package.appxmanifest` para permitir que la aplicación se inicie mediante una URI específica.

```xml
<!-- Package.appxmanifest -->
<Package ...>
  <Applications>
    <Application ...>
      <Extensions>
        <uap:Extension Category="windows.protocol">
          <uap:Protocol Name="myapp">
            <uap:DisplayName>MyApp Protocol</uap:DisplayName>
          </uap:Protocol>
        </uap:Extension>
      </Extensions>
    </Application>
  </Applications>
</Package>
```

**Explicación del Código:**

* **Protocol Name:** Define el esquema de URI que la aplicación reconocerá (por ejemplo, `myapp://`).
* **DisplayName:** Nombre descriptivo del protocolo.

### Paso 2: Crear la Página de Detalle de la Cita/Eventos

Implementamos una página (`AppointmentDetailPage`) que mostrará los detalles de una cita o evento específico.

```csharp
// AppointmentDetailPage.xaml.cs
public sealed partial class AppointmentDetailPage : Page
{
    private readonly AppointmentService _appointmentService;
    private int _appointmentId;

    public AppointmentDetailPage()
    {
        this.InitializeComponent();
        _appointmentService = App.Services.GetService<AppointmentService>();
    }

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        if (e.Parameter is int appointmentId)
        {
            _appointmentId = appointmentId;
            var appointment = await _appointmentService.GetAppointmentsAsync(DateTime.Now)
                                                     .ContinueWith(t => t.Result.FirstOrDefault(a => a.Id == _appointmentId));

            if (appointment != null)
            {
                // Asignar los detalles de la cita al ViewModel o controles de la UI
                // Ejemplo:
                AppointmentNameTextBlock.Text = appointment.Name;
                AppointmentDateTextBlock.Text = appointment.Date.ToString("f");
                // ...
            }
            else
            {
                // Manejar el caso donde la cita no se encuentra
                var dialog = new MessageDialog("La cita no fue encontrada.");
                await dialog.ShowAsync();
                Frame.GoBack();
            }
        }
    }
}
```

**Explicación del Código:**

* **Inyección de Dependencias:**
  * Obtenemos una instancia de `AppointmentService` desde el contenedor de servicios.
* **Obtención de la Cita:**
  * Al recibir el `appointmentId` como parámetro de navegación, obtenemos los detalles de la cita correspondiente.
* **Actualización de la Interfaz de Usuario:**
  * Asignamos los detalles de la cita a los controles de la interfaz de usuario para mostrar la información relevante.

### Paso 3: Lanzar la Aplicación desde una Cita/Eventos Externos

Para probar la apertura de la aplicación desde una cita o evento, puedes utilizar herramientas como **URI Scheme Tester** o simplemente crear una URI personalizada que invoque el protocolo definido.

**Ejemplo de URI:**

```
myapp://appointment?id=123
```

Al ejecutar esta URI, Windows iniciará la aplicación UWP y navegará automáticamente a la página de detalle de la cita con `id=123`.

### Paso 4: Actualizar los Servicios Necesarios

Asegúrate de que todos los servicios utilizados (como `AppointmentService`, `ICalendarProvider`, etc.) estén correctamente registrados y configurados en `App.xaml.cs`. Esto garantiza que cualquier parte de la aplicación que necesite estos servicios pueda acceder a ellos sin problemas.

```csharp
// App.xaml.cs (Extracto relevante)
private void ConfigureServices()
{
    var serviceCollection = new ServiceCollection();

    // Registro de proveedores
    serviceCollection.AddSingleton<ICalendarProvider, CalendarProvider>();
    serviceCollection.AddSingleton<IProjectRepository, ProjectRepository>();

    // Registro de servicios
    serviceCollection.AddSingleton<AppointmentService>();
    serviceCollection.AddSingleton<ProjectHelper>();

    // Registro de ViewModels y otros servicios según sea necesario
    // serviceCollection.AddTransient<MainViewModel>();
    // serviceCollection.AddTransient<SettingsViewModel>();
    // ...

    Services = serviceCollection.BuildServiceProvider();
}
```

## Modificación de `JumpListHelper.cs`

Para mejorar la experiencia de usuario y facilitar la navegación, modificamos la clase `JumpListHelper.cs` para incluir una sobrecarga que agrupe elementos por un "número" y muestre los títulos de los grupos. Esto permite organizar mejor las entradas en la Jump List de la aplicación.

```csharp
// JumpListHelper.cs
using Windows.UI.StartScreen;
using System.Collections.Generic;

public static class JumpListHelper
{
    public static async Task AddGroupToJumpListAsync(string groupName, IEnumerable<string> items)
    {
        var jumpList = await JumpList.LoadCurrentAsync();
        jumpList.Items.Clear();
        jumpList.Groups.Clear();

        var jumpListGroup = new JumpListGroup(groupName);
        jumpList.Groups.Add(jumpListGroup);

        foreach (var item in items)
        {
            var jumpListItem = JumpListItem.CreateWithArguments($"action=openItem&name={item}", item);
            jumpListItem.Group = jumpListGroup;
            jumpList.Items.Add(jumpListItem);
        }

        await jumpList.SaveAsync();
    }

    // Sobrecarga para agrupar por número
    public static async Task AddNumberGroupedItemsToJumpListAsync(Dictionary<int, List<string>> groupedItems)
    {
        var jumpList = await JumpList.LoadCurrentAsync();
        jumpList.Items.Clear();
        jumpList.Groups.Clear();

        foreach (var group in groupedItems)
        {
            string groupName = $"Grupo {group.Key}";
            var jumpListGroup = new JumpListGroup(groupName);
            jumpList.Groups.Add(jumpListGroup);

            foreach (var item in group.Value)
            {
                var jumpListItem = JumpListItem.CreateWithArguments($"action=openItem&name={item}", item);
                jumpListItem.Group = jumpListGroup;
                jumpList.Items.Add(jumpListItem);
            }
        }

        await jumpList.SaveAsync();
    }
}
```

**Explicación del Código:**

* **Método `AddGroupToJumpListAsync`:**
  * Permite agregar un grupo de elementos a la Jump List con un nombre de grupo específico.
* **Sobrecarga `AddNumberGroupedItemsToJumpListAsync`:**
  * Acepta un diccionario donde la clave es un número que representa el grupo y el valor es una lista de elementos pertenecientes a ese grupo.
  * Crea grupos nombrados como "Grupo {número}" y agrega los elementos correspondientes a cada grupo en la Jump List.

**Uso de la Sobrecarga:**

```csharp
// Ejemplo de uso en App.xaml.cs o en cualquier otra parte de la aplicación
public async Task InitializeJumpListAsync()
{
    var groupedItems = new Dictionary<int, List<string>>
    {
        { 1, new List<string> { "Proyecto A", "Proyecto B" } },
        { 2, new List<string> { "Proyecto C", "Proyecto D" } }
    };

    await JumpListHelper.AddNumberGroupedItemsToJumpListAsync(groupedItems);
}
```

## Integración Completa en `App.xaml.cs`

Aseguramos que todos los servicios y configuraciones se inicialicen correctamente al iniciar la aplicación.

```csharp
// App.xaml.cs
sealed partial class App : Application
{
    public static IServiceProvider Services { get; private set; }

    public App()
    {
        this.InitializeComponent();
        this.Suspending += OnSuspending;
        ConfigureServices();
    }

    private void ConfigureServices()
    {
        var serviceCollection = new ServiceCollection();

        // Registro de proveedores
        serviceCollection.AddSingleton<ICalendarProvider, CalendarProvider>();
        serviceCollection.AddSingleton<IProjectRepository, ProjectRepository>();

        // Registro de servicios
        serviceCollection.AddSingleton<AppointmentService>();
        serviceCollection.AddSingleton<ProjectHelper>();

        // Registro de ViewModels y otros servicios según sea necesario
        // serviceCollection.AddTransient<MainViewModel>();
        // serviceCollection.AddTransient<SettingsViewModel>();
        // ...

        Services = serviceCollection.BuildServiceProvider();
    }

    protected override async void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;

        if (rootFrame == null)
        {
            rootFrame = new Frame();
            rootFrame.NavigationFailed += OnNavigationFailed;

            Window.Current.Content = rootFrame;
        }

        if (e.PrelaunchActivated == false)
        {
            if (rootFrame.Content == null)
            {
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            Window.Current.Activate();
        }

        // Manejo de apertura desde una cita/evento
        HandleActivation(e);

        // Inicializar JumpList con grupos numerados
        await InitializeJumpListAsync();
    }

    private async Task InitializeJumpListAsync()
    {
        var groupedItems = new Dictionary<int, List<string>>
        {
            { 1, new List<string> { "Proyecto A", "Proyecto B" } },
            { 2, new List<string> { "Proyecto C", "Proyecto D" } }
        };

        await JumpListHelper.AddNumberGroupedItemsToJumpListAsync(groupedItems);
    }

    private void HandleActivation(IActivatedEventArgs args)
    {
        if (args.Kind == ActivationKind.Protocol)
        {
            var protocolArgs = args as ProtocolActivatedEventArgs;
            string uri = protocolArgs.Uri.ToString();

            // Parsear la URI para determinar la acción
            // Ejemplo de URI: myapp://appointment?id=123
            var uriScheme = new Uri(uri);
            if (uriScheme.Host.Equals("appointment", StringComparison.OrdinalIgnoreCase))
            {
                var queryParams = Microsoft.Toolkit.Uwp.Helpers.SystemNavigationHelper.ParseQueryString(uriScheme.Query);
                if (queryParams.ContainsKey("id") && int.TryParse(queryParams["id"], out int appointmentId))
                {
                    var frame = Window.Current.Content as Frame;
                    frame.Navigate(typeof(AppointmentDetailPage), appointmentId);
                }
            }
        }
    }

    private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
    {
        throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
    }

    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        // Guardar el estado de la aplicación
    }
}
```

**Explicación del Código:**

1. **Inicialización de JumpList:**
   * Después de lanzar la aplicación, inicializamos la Jump List con grupos numerados utilizando el método `InitializeJumpListAsync`.
   * Esto organiza los proyectos en grupos, mejorando la navegación rápida a través de la Jump List.
2. **Manejo de Activación desde Protocolos:**
   * Al detectar una activación de tipo protocolo (por ejemplo, desde una cita/evento), parseamos la URI y navegamos a la página de detalle correspondiente.
3. **Registro y Uso de Servicios:**
   * Todos los servicios necesarios están registrados en el contenedor de servicios y son accesibles globalmente a través de `App.Services`.

## Apertura desde una Cita/Eventos

La funcionalidad de abrir la aplicación desde una cita o evento permite a los usuarios acceder directamente a la información relevante sin tener que navegar manualmente. A continuación, se detalla cómo implementar esta funcionalidad.

### Paso 1: Definir el Protocolo de Activación

Asegúrate de que el protocolo de activación (`myapp://`) esté definido en el archivo `Package.appxmanifest` como se mostró anteriormente.

### Paso 2: Implementar la Navegación en `App.xaml.cs`

Como se explicó anteriormente, el método `HandleActivation` en `App.xaml.cs` se encarga de detectar y manejar la activación desde una cita/evento.

### Paso 3: Crear la Página de Detalle de la Cita/Eventos

Implementa la página `AppointmentDetailPage` que mostrará los detalles de la cita o evento seleccionado.

```csharp
// AppointmentDetailPage.xaml.cs
public sealed partial class AppointmentDetailPage : Page
{
    private readonly AppointmentService _appointmentService;
    private int _appointmentId;

    public AppointmentDetailPage()
    {
        this.InitializeComponent();
        _appointmentService = App.Services.GetService<AppointmentService>();
    }

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        if (e.Parameter is int appointmentId)
        {
            _appointmentId = appointmentId;
            var appointment = await _appointmentService.GetAppointmentsAsync(DateTime.Now)
                                                     .ContinueWith(t => t.Result.FirstOrDefault(a => a.Id == _appointmentId));

            if (appointment != null)
            {
                // Asignar los detalles de la cita al ViewModel o controles de la UI
                AppointmentNameTextBlock.Text = appointment.Name;
                AppointmentDateTextBlock.Text = appointment.Date.ToString("f");
                // ...
            }
            else
            {
                // Manejar el caso donde la cita no se encuentra
                var dialog = new MessageDialog("La cita no fue encontrada.");
                await dialog.ShowAsync();
                Frame.GoBack();
            }
        }
    }
}
```

### Paso 4: Probar la Activación desde una Cita/Eventos

Para probar que la aplicación maneja correctamente la apertura desde una cita/evento, puedes crear una URI personalizada y ejecutarla.

**Ejemplo de URI:**

```
myapp://appointment?id=123
```

Al ejecutar esta URI (por ejemplo, ingresándola en el navegador), Windows iniciará la aplicación y navegará automáticamente a la página `AppointmentDetailPage`, mostrando los detalles de la cita con `id=123`.

## Consideraciones Finales

Implementar correctamente el **inicio de la aplicación** y manejar activaciones desde citas o eventos asegura que los usuarios puedan interactuar con la aplicación de manera eficiente y directa. Al registrar e inicializar los servicios necesarios en `App.xaml.cs`, garantizamos que toda la funcionalidad esté disponible desde el principio, mejorando la estabilidad y la experiencia de usuario.

Además, al personalizar la Jump List y manejar transiciones de manera eficiente, proporcionamos una navegación fluida y organizada, facilitando el acceso rápido a las secciones más importantes de la aplicación.

**Recomendaciones:**

* **Pruebas Exhaustivas:** Asegúrate de probar la activación desde diferentes tipos de citas/eventos para garantizar que la navegación funcione correctamente en todos los casos.
* **Optimización de Servicios:** Mantén los servicios optimizados para evitar retrasos en el inicio de la aplicación o durante la navegación.
* **Consistencia en la Navegación:** Mantén un flujo de navegación coherente para que los usuarios puedan predecir y comprender cómo moverse a través de la aplicación.

Con estas implementaciones y consideraciones, lograrás que tu aplicación UWP ofrezca una experiencia de usuario robusta, eficiente y personalizada desde el inicio.
