> 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/tiles-secundarios.md).

# Tiles Secundarios

Los **Tiles Secundarios** son una característica poderosa de las aplicaciones UWP que permiten a los usuarios anclar contenido específico de la aplicación directamente en la pantalla de inicio de Windows. A diferencia de los *tiles* principales, que representan la aplicación en su totalidad, los *tiles* secundarios pueden apuntar a páginas o secciones específicas dentro de la aplicación, ofreciendo un acceso rápido y directo a contenidos relevantes.

En esta sección, exploraremos cómo implementar y gestionar *Tiles Secundarios* en una aplicación UWP siguiendo el patrón **MVVM**. Además, abordaremos cómo manejar la navegación desde estos *tiles* y cómo integrarlos eficazmente en la experiencia de usuario de la aplicación.

## ¿Qué son los Tiles Secundarios?

Los *Tiles Secundarios* permiten a las aplicaciones UWP crear accesos directos personalizados en la pantalla de inicio de Windows que apuntan a ubicaciones específicas dentro de la aplicación. Por ejemplo, una aplicación de gestión de proyectos podría permitir a los usuarios anclar un proyecto específico directamente en la pantalla de inicio para acceder rápidamente a sus detalles.

## Beneficios de Utilizar Tiles Secundarios

* **Acceso Rápido:** Permiten a los usuarios acceder rápidamente a secciones o contenidos específicos sin tener que navegar manualmente dentro de la aplicación.
* **Personalización:** Ofrecen una experiencia más personalizada al permitir a los usuarios destacar contenidos que consideran importantes.
* **Mejora de la Experiencia de Usuario:** Facilitan una interacción más eficiente y fluida con la aplicación.

## Implementación de Tiles Secundarios en MVVM

A continuación, se detalla cómo implementar *Tiles Secundarios* en una aplicación UWP siguiendo el patrón **MVVM**.

### Paso 1: Definir el Modelo de Datos

Primero, definimos el modelo de datos que representará el contenido que se anclará en los *tiles* secundarios. Por ejemplo, un proyecto en una aplicación de gestión de proyectos.

```csharp
public class Project
{
    public int Id { get; set; }
    public string Name { get; set; }
    // Otras propiedades relevantes
}
```

### Paso 2: Crear el ViewModel para Gestionar Tiles Secundarios

El *ViewModel* debe manejar la lógica para crear y eliminar *Tiles Secundarios*. Utilizaremos el servicio de **SecondaryTile** proporcionado por UWP para gestionar estos *tiles*.

```csharp
using Windows.UI.StartScreen;
using Windows.UI.Popups;

public class ProjectDetailViewModel : INotifyPropertyChanged
{
    public Project CurrentProject { get; set; }

    public ProjectDetailViewModel(Project project)
    {
        CurrentProject = project;
    }

    public async Task CreateSecondaryTileAsync()
    {
        string tileId = $"Project_{CurrentProject.Id}";
        string displayName = CurrentProject.Name;
        string arguments = $"action=viewProject&id={CurrentProject.Id}";

        Uri square150x150Logo = new Uri("ms-appx:///Assets/Square150x150Logo.png");
        Uri square44x44Logo = new Uri("ms-appx:///Assets/Square44x44Logo.png");

        SecondaryTile secondaryTile = new SecondaryTile(
            tileId,
            displayName,
            arguments,
            square150x150Logo,
            TileSize.Square150x150
        );

        secondaryTile.VisualElements.Square44x44Logo = square44x44Logo;
        secondaryTile.VisualElements.ShowNameOnSquare150x150Logo = true;

        bool isPinned = await secondaryTile.RequestCreateAsync();

        if (isPinned)
        {
            // Notificar al usuario que el tile se ha creado exitosamente
            var dialog = new MessageDialog("Tile secundario creado correctamente.");
            await dialog.ShowAsync();
        }
        else
        {
            // Notificar al usuario que la creación del tile fue cancelada
            var dialog = new MessageDialog("La creación del tile secundario fue cancelada.");
            await dialog.ShowAsync();
        }
    }

    public async Task DeleteSecondaryTileAsync()
    {
        string tileId = $"Project_{CurrentProject.Id}";
        SecondaryTile secondaryTile = new SecondaryTile(tileId);

        bool isUnpinned = await secondaryTile.RequestDeleteAsync();

        if (isUnpinned)
        {
            // Notificar al usuario que el tile se ha eliminado exitosamente
            var dialog = new MessageDialog("Tile secundario eliminado correctamente.");
            await dialog.ShowAsync();
        }
        else
        {
            // Notificar al usuario que la eliminación del tile fue cancelada
            var dialog = new MessageDialog("La eliminación del tile secundario fue cancelada.");
            await dialog.ShowAsync();
        }
    }

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

### Paso 3: Configurar la Vista de Detalle del Proyecto

En la vista de detalle del proyecto (`ProjectDetailPage.xaml`), añadimos un botón para crear un *tile* secundario y otro para eliminarlo. Este botón estará vinculado a los comandos del *ViewModel*.

```xml
<Page
    x:Class="MyApp.ProjectDetailPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp"
    xmlns:vm="using:MyApp.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.DataContext>
        <vm:ProjectDetailViewModel x:Name="ViewModel" />
    </Page.DataContext>

    <Grid Padding="20">
        <StackPanel>
            <TextBlock Text="{Binding CurrentProject.Name}" FontSize="24" FontWeight="Bold" />
            <!-- Otros detalles del proyecto -->

            <Button Content="Agregar a Biblioteca" Click="AddToLibraryButton_Click" Margin="0,20,0,0"/>
            <Button Content="Eliminar de Biblioteca" Click="RemoveFromLibraryButton_Click" Margin="0,10,0,0"/>
        </StackPanel>
    </Grid>
</Page>
```

```csharp
// ProjectDetailPage.xaml.cs
public sealed partial class ProjectDetailPage : Page
{
    public ProjectDetailViewModel ViewModel => DataContext as ProjectDetailViewModel;

    public ProjectDetailPage()
    {
        this.InitializeComponent();
    }

    private async void AddToLibraryButton_Click(object sender, RoutedEventArgs e)
    {
        await ViewModel.CreateSecondaryTileAsync();
    }

    private async void RemoveFromLibraryButton_Click(object sender, RoutedEventArgs e)
    {
        await ViewModel.DeleteSecondaryTileAsync();
    }
}
```

### Paso 4: Manejar la Navegación desde Tiles Secundarios

Cuando el usuario hace clic en un *tile* secundario, la aplicación debe navegar a la página de detalle del proyecto correspondiente. Para lograr esto, debemos manejar los argumentos pasados al lanzar la aplicación desde un *tile* secundario.

```csharp
// App.xaml.cs
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 (e.TileId != "App")
        {
            // Lanzamiento desde un tile secundario
            var args = e.Arguments; // "action=viewProject&id=1"
            var query = Microsoft.Toolkit.Uwp.Helpers.SystemNavigationHelper.ParseQueryString(args);
            if (query.ContainsKey("action") && query["action"] == "viewProject" && query.ContainsKey("id"))
            {
                int projectId;
                if (int.TryParse(query["id"], out projectId))
                {
                    rootFrame.Navigate(typeof(ProjectDetailPage), projectId);
                }
            }
        }
        else
        {
            if (rootFrame.Content == null)
            {
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
        }
        Window.Current.Activate();
    }
}
```

En este código, al detectar que la aplicación se ha lanzado desde un *tile* secundario (verificando que `e.TileId` no sea `"App"`), se extraen los argumentos para determinar qué página navegar. En este caso, se navega a `ProjectDetailPage` pasando el `projectId` correspondiente.

### Paso 5: Configurar la Navegación en la MainPage

En la `MainPage`, comentaremos la redirección a la página de detalle de proyectos y la funcionalidad del botón “Library”.

```xml
<Page
    x:Class="MyApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp"
    xmlns:vm="using:MyApp.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.DataContext>
        <vm:MainViewModel x:Name="ViewModel"/>
    </Page.DataContext>

    <Grid>
        <StackPanel>
            <!-- Lista de Proyectos -->
            <ListView ItemsSource="{Binding Projects}"
                      IsItemClickEnabled="True"
                      SelectionMode="Single"
                      ItemClick="ProjectsListView_ItemClick">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Project">
                        <StackPanel Margin="10">
                            <TextBlock Text="{x:Bind Name}" FontSize="18" FontWeight="Bold"/>
                            <!-- Otras propiedades del proyecto -->
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

            <!-- Botón Library para Navegar a la Página Principal -->
            <Button Content="Library" Click="LibraryButton_Click" Margin="0,20,0,0"/>
        </StackPanel>
    </Grid>
</Page>
```

```csharp
// MainPage.xaml.cs
public sealed partial class MainPage : Page
{
    public MainViewModel ViewModel => DataContext as MainViewModel;

    public MainPage()
    {
        this.InitializeComponent();
    }

    private void ProjectsListView_ItemClick(object sender, ItemClickEventArgs e)
    {
        if (e.ClickedItem is Project clickedProject)
        {
            Frame.Navigate(typeof(ProjectDetailPage), clickedProject.Id);
        }
    }

    private void LibraryButton_Click(object sender, RoutedEventArgs e)
    {
        // Navegar a la página principal desde el detalle del proyecto
        Frame.Navigate(typeof(MainPage));
    }
}
```

**Comentarios Clave:**

* **Botón “Library”:** En la `ProjectDetailPage`, el botón “Library” permite al usuario navegar de vuelta a la `MainPage`. Esto facilita una navegación fluida y coherente dentro de la aplicación.

  ```csharp
  private async void LibraryButton_Click(object sender, RoutedEventArgs e)
  {
      await ViewModel.NavigateToMainPageAsync();
  }
  ```
* **Redirección a la Página de Detalle de Proyectos:** En la `MainPage`, al hacer clic en un proyecto dentro de la `ListView`, la aplicación navega a la `ProjectDetailPage` pasando el `projectId`. Esto permite que la aplicación muestre detalles específicos del proyecto seleccionado.

  ```csharp
  private void ProjectsListView_ItemClick(object sender, ItemClickEventArgs e)
  {
      if (e.ClickedItem is Project clickedProject)
      {
          Frame.Navigate(typeof(ProjectDetailPage), clickedProject.Id);
      }
  }
  ```

## Integración con la Sección “Inicio de la Aplicación”

Es importante destacar que la funcionalidad de los *Tiles Secundarios* está estrechamente relacionada con la sección **“Inicio de la Aplicación”** del capítulo 9. En dicha sección, se aborda cómo manejar la inicialización de la aplicación, incluyendo cómo detectar si la aplicación ha sido lanzada desde un *tile* secundario y cómo navegar a la página correspondiente. Asegúrate de revisar esa sección para entender completamente cómo se integra la navegación desde los *tiles* secundarios con el flujo general de la aplicación.

## Buenas Prácticas en la Implementación de Tiles Secundarios

Para asegurar una implementación efectiva y mantenible de los *Tiles Secundarios*, considera las siguientes buenas prácticas:

* **Identificadores Únicos:** Utiliza identificadores únicos para cada *tile* secundario para evitar conflictos y facilitar la gestión de los mismos.
* **Optimización de Imágenes:** Asegúrate de que las imágenes utilizadas en los *tiles* sean optimizadas para reducir el consumo de recursos y mejorar la carga.
* **Manejo de Errores:** Implementa mecanismos para manejar casos en los que la creación o eliminación de *tiles* falle, proporcionando retroalimentación clara al usuario.
* **Actualización de Tiles:** Considera la posibilidad de actualizar dinámicamente el contenido de los *tiles* secundarios para reflejar cambios en los datos de la aplicación.
* **Consistencia en la Navegación:** Asegúrate de que la navegación desde los *tiles* secundarios sea coherente y proporcione una experiencia de usuario fluida.

## Ejemplo Práctico: Creación y Uso de Tiles Secundarios

A continuación, se presenta un ejemplo completo que integra la creación de un *tile* secundario desde la vista de detalle de un proyecto y la navegación a la página de detalle al hacer clic en el *tile*.

### Crear un Tile Secundario desde la Vista de Detalle

En la `ProjectDetailPage.xaml`, el usuario puede optar por agregar el proyecto actual a su biblioteca anclándolo como un *tile* secundario.

```xml
<Button Content="Agregar a Biblioteca" Click="AddToLibraryButton_Click" Margin="0,20,0,0"/>
```

```csharp
// ProjectDetailPage.xaml.cs
private async void AddToLibraryButton_Click(object sender, RoutedEventArgs e)
{
    await ViewModel.CreateSecondaryTileAsync();
}
```

### Navegar a la Página de Detalle desde el Tile Secundario

Cuando el usuario hace clic en el *tile* secundario, la aplicación se lanza y navega automáticamente a la `ProjectDetailPage` correspondiente al proyecto anclado.

```csharp
// App.xaml.cs
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 (e.TileId != "App")
        {
            // Lanzamiento desde un tile secundario
            var args = e.Arguments; // "action=viewProject&id=1"
            var query = Microsoft.Toolkit.Uwp.Helpers.SystemNavigationHelper.ParseQueryString(args);
            if (query.ContainsKey("action") && query["action"] == "viewProject" && query.ContainsKey("id"))
            {
                int projectId;
                if (int.TryParse(query["id"], out projectId))
                {
                    rootFrame.Navigate(typeof(ProjectDetailPage), projectId);
                }
            }
        }
        else
        {
            if (rootFrame.Content == null)
            {
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
        }
        Window.Current.Activate();
    }
}
```

En este ejemplo, al detectar que la aplicación ha sido lanzada desde un *tile* secundario (verificando que `e.TileId` no sea `"App"`), se extraen los argumentos para determinar qué página navegar. En este caso, se navega a `ProjectDetailPage` pasando el `projectId` correspondiente.

## Consideraciones Finales

La implementación de **Tiles Secundarios** en una aplicación UWP siguiendo el patrón **MVVM** permite una experiencia de usuario más personalizada y eficiente. Al permitir que los usuarios anclen contenidos específicos directamente en la pantalla de inicio, se mejora la accesibilidad y se facilita el acceso rápido a la información relevante.

Al seguir las buenas prácticas y asegurar una integración coherente con el flujo de navegación de la aplicación, los *Tiles Secundarios* pueden convertirse en una herramienta valiosa para mejorar la interacción y satisfacción del usuario.

**Ver también:** [Inicio de la Aplicación](#inicio-de-la-aplicación)
