15 - Menú lateral con íconos y varias páginas.


Una estructura muy común en las aplicaciones universales de Windows es la disposición de un menú del lado izquierdo de la pantalla representado por un conjunto de íconos.

Normalmente el primer ícono que tiene es similar a:

icono de apertura del menu

Básicamente tres líneas paralelas (con un color de fondo que puede variar de aplicación en aplicación)

Por debajo de dicho ícono aparecen los otros íconos propios de nuestro menú:

icono de apertura del menu

Cuando se presiona este botón aparece al lado de cada ícono una descripción del mismo:

icono de apertura del menu

Solo el primer ícono tiene como funcionalidad expandir o contraer el menú lateral. Los otros íconos tienen por objetivo ejecutar los algoritmos propios de nuestra aplicación.

Problema

Implementar un menú lateral que muestre cuatro íconos, el primero para expandir o contraer el menú lateral y los otros tres para abrir tres páginas distintas.

Como primer paso creamos un nuevo proyecto llamado "Proyecto20" seleccionando desde el menú de opciones del Visual Studio: Archivo -> Nuevo -> Proyecto.

El primer archivo que modificamos es el MainPage.xaml con el siguiente código:

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

    <SplitView  x:Name="splitView1" 
                DisplayMode="CompactOverlay"  
                IsPaneOpen="False" 
                CompactPaneLength="50" 
                OpenPaneLength="200">
        <SplitView.Pane>
            <StackPanel Background="LightGray">
                <Button x:Name="botonMenu" 
                        FontFamily="Segoe MDL2 Assets" 
                        Content=""
                        Width="50" 
                        Height="50" 
                        Background="Transparent"
                        Click="botonMenu_Click"
                        />
                <StackPanel Orientation="Horizontal">
                    <Button x:Name="boton1" 
                            FontFamily="Segoe MDL2 Assets" 
                            Content=""
                            Width="50" 
                            Height="50" 
                            Background="Transparent" 
                            Click="boton1_Click"
                            />
                    <TextBlock Text="Descripción 1" 
                               FontSize="18" 
                               VerticalAlignment="Center" />
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Button x:Name="boton2" 
                            FontFamily="Segoe MDL2 Assets" 
                            Content=""
                            Width="50"
                            Height="50" 
                            Background="Transparent" 
                            Click="boton2_Click"
                            />
                    <TextBlock Text="Descripción 2"
                               FontSize="18"
                               VerticalAlignment="Center"  />
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Button x:Name="boton3" 
                            FontFamily="Segoe MDL2 Assets"
                            Content=""
                            Width="50" 
                            Height="50"
                            Background="Transparent"
                            Click="boton3_Click"
                            />
                    <TextBlock Text="Descripción 3"
                               FontSize="18"
                               VerticalAlignment="Center" />
                </StackPanel>
            </StackPanel>
        </SplitView.Pane>
        <SplitView.Content>
            <Frame x:Name="frame1"/>
        </SplitView.Content>
    </SplitView>
</Page>

Gran parte de este código lo hemos visto al explicar el control SplitView y Frame.

Nuestro Contenedor principal es el SplitView donde le definimos un "Name" e indicamos el ancho de 50 píxeles cuando se encuentra semicerrado y de 200 cuando se encuentra abierto, también cargamos el valor "CompactOverlay" en la propiedad DisplayMode para indicar que el panel siempre está visible:

    <SplitView  x:Name="splitView1" 
                DisplayMode="CompactOverlay"  
                IsPaneOpen="False" 
                CompactPaneLength="50" 
                OpenPaneLength="200">

En la sección Pane del SplitView insertamos un StackPanel del color gris claro:

        <SplitView.Pane>
            <StackPanel Background="LightGray">

Dentro de este StackPanel definimos el primer botón que tendrá por objetivo expandir o contraer el menú lateral:

               <Button x:Name="botonMenu" 
                        FontFamily="Segoe MDL2 Assets" 
                        Content="&#xE700;"
                        Width="50" 
                        Height="50" 
                        Background="Transparent"
                        Click="botonMenu_Click"
                        />

Lo más conveniente es utilizar íconos que trae por defecto Windows 10 que se encuentran contenidos en la fuente "Segoe MDL2 Assets".

Para ver los íconos de esta fuente podemos arrancar el programa "Mapa de caracteres" que viene con Windows 10, lo podemos buscar desde el ícono de "Buscar":

programa mapa de caracteres

Seleccionamos la fuente "Segoe MDL2 Assets":

programa mapa de caracteres

Seguidamente buscamos el código que tienen asignado los íconos que mostraremos en los botones:

programa mapa de caracteres

Este valor lo indicamos en la propiedad Content antecediendo los caracteres &#x y finalizando con el caracter ;

                <Button x:Name="botonMenu" 
                        FontFamily="Segoe MDL2 Assets" 
                        Content="&#xE700;"
                        Width="50" 
                        Height="50" 
                        Background="Transparent"
                        Click="botonMenu_Click"
                        />

De forma similar buscamos los código para los íconos de los otros tres botones.

Como los botones para las acciones mostraremos una descripción a su lado disponemos unos StackPanel horizontales para insertar el Button y un TextBlock con la descripción.

El primer ícono con la descripción lo definimos:

                <StackPanel Orientation="Horizontal">
                    <Button x:Name="boton1" 
                            FontFamily="Segoe MDL2 Assets" 
                            Content="&#xE825;"
                            Width="50" 
                            Height="50" 
                            Background="Transparent" 
                            Click="boton1_Click"
                            />
                    <TextBlock Text="Descripción 1" 
                               FontSize="18" 
                               VerticalAlignment="Center" />
                </StackPanel>

De forma similar hacemos para disponer los otros dos botones con sus descripciones:

                <StackPanel Orientation="Horizontal">
                    <Button x:Name="boton2" 
                            FontFamily="Segoe MDL2 Assets" 
                            Content="&#xE11A;"
                            Width="50"
                            Height="50" 
                            Background="Transparent" 
                            Click="boton2_Click"
                            />
                    <TextBlock Text="Descripción 2"
                               FontSize="18"
                               VerticalAlignment="Center"  />
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Button x:Name="boton3" 
                            FontFamily="Segoe MDL2 Assets"
                            Content="&#xE115;"
                            Width="50" 
                            Height="50"
                            Background="Transparent"
                            Click="boton3_Click"
                            />
                    <TextBlock Text="Descripción 3"
                               FontSize="18"
                               VerticalAlignment="Center" />
                </StackPanel>

En la parte de contenido del SplitView dispondremos un Frame que se encargará de mostrar las distintas páginas como hemos visto en conceptos anteriores:

        <SplitView.Content>
            <Frame x:Name="frame1"/>
        </SplitView.Content>

Por ahora no hemos codificado nada en los eventos Click de cada uno de los cuatro botones, si ejecutamos la aplicación podemos ver una pantalla similar a esta:

menu lateral

No tiene ninguna funcionalidad por el momento.

El siguiente paso será implementar la funcionalidad del evento Click del botón que expandirá o contraerá el menú lateral. Para esto implementamos el siguiente código en el archivo MainPage.xaml.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
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;

// La plantilla de elemento Página en blanco está documentada en https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0xc0a

namespace Proyecto20
{
    /// <summary>
    /// Página vacía que se puede usar de forma independiente o a la que se puede navegar dentro de un objeto Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private void botonMenu_Click(object sender, RoutedEventArgs e)
        {
            if (splitView1.IsPaneOpen == true)
                splitView1.IsPaneOpen = false;
            else
                splitView1.IsPaneOpen = true;
        }

        private void boton1_Click(object sender, RoutedEventArgs e)
        {

        }

        private void boton2_Click(object sender, RoutedEventArgs e)
        {

        }

        private void boton3_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}

Como vimos en un concepto anterior preguntamos por el estado del la propiedad IsPaneOpen y dependiendo de esto cambiamos por el valor contrario:

        private void botonMenu_Click(object sender, RoutedEventArgs e)
        {
            if (splitView1.IsPaneOpen == true)
                splitView1.IsPaneOpen = false;
            else
                splitView1.IsPaneOpen = true;
        }

Ahora si ejecutamos nuevamente nuestra aplicación podremos presionar el primer botón del menú y veremos que podemos abrir el menú lateral para ver la descripción de cada ícono:

menu lateral

Para implementar la funcionalidad de las tres opciones siguientes debemos agregar tres páginas nuevas a nuestra aplicación como vimos en el concepto anterior.

Recordemos que seleccionamos desde el menú de opciones del Visual Studio: Proyecto -> Agregar nuevo elemento... y en el diálogo que aparece seleccionamos "Página en blanco" y definimos su nombre (en nuestro caso las llamaremos "Pagina1.xaml", "Pagina2.xaml" y "Pagina3.xaml"):

menu lateral

Este proceso lo repetimos tres veces para crear las tres páginas.

Ahora dispondremos un TextBlock en cada una de estás página indicando como contenido el número de página que se trata:

menu lateral

El código fuente de cada archivo XAML de las páginas es:

Pagina1.xaml

<Page
    x:Class="Proyecto20.Pagina1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Proyecto20"
    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>
        <TextBlock Text="Página 1" FontSize="55" />
    </Grid>
</Page>

Pagina2.xaml

<Page
    x:Class="Proyecto20.Pagina2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Proyecto20"
    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>
        <TextBlock Text="Página 2" FontSize="55" />
    </Grid>
</Page>

Pagina3.xaml

<Page
    x:Class="Proyecto20.Pagina3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Proyecto20"
    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>
        <TextBlock Text="Página 3" FontSize="55" />
    </Grid>
</Page>

Por último nos falta modificar el archivo MainPage.xaml.cs para capturar el evento Click de cada uno de los botones e indicar que página debe mostrarse en el Frame:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
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;

// La plantilla de elemento Página en blanco está documentada en http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace Proyecto20
{
    /// 
    /// Página vacía que se puede usar de forma independiente o a la que se puede navegar dentro de un objeto Frame.
    /// 
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            frame1.Navigate(typeof(Pagina1));
        }

        private void botonMenu_Click(object sender, RoutedEventArgs e)
        {
            if (splitView1.IsPaneOpen == true)
                splitView1.IsPaneOpen = false;
            else
                splitView1.IsPaneOpen = true;
        }

        private void boton1_Click(object sender, RoutedEventArgs e)
        {
            frame1.Navigate(typeof(Pagina1));
        }

        private void boton2_Click(object sender, RoutedEventArgs e)
        {
            frame1.Navigate(typeof(Pagina2));
        }

        private void boton3_Click(object sender, RoutedEventArgs e)
        {
            frame1.Navigate(typeof(Pagina3));
        }
    }
}

Ahora si cuando presionamos alguno de los íconos se activa la página respectiva:

menu lateral

La única contra que podríamos encontrar en este estilo de menú lateral es que cuando se encuentra expandido mostrando la descripción del ícono para ejecutar la acción hay que presionar el ícono y no funciona si presionamos la descripción (ya que esta es un TextBlock), en conceptos futuros veremos como implementar este menú con la descripción que se pueda presionar.

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

Retornar