MSDN España

Noticias, avisos, reflexiones... del equipo que hay detrás de MSDN en España... también tendremos alguna que otra firma invitada :)

Windows 8 Tips & Tricks. Mostrar mensajes con popups (XAML/C#

Windows 8 Tips & Tricks. Mostrar mensajes con popups (XAML/C#)

[Nota: Este artículo pertenece a nuestra serie de Windows 8 Tips & Tricks]

Un consejo que damos a todo aquel que desarrolla una aplicación para Windows 8 es evitar abusar en la medida de lo posible de los Windows.UI.Popups.MessageDialog para mostrar mensajes comunes al usuario. Son demasiado disruptivos, y la mayor parte de las veces innecesarios. Una buena alternativa es mostrar un popup con dicho mensaje, y en este Tips & Tricks te enseñamos como hacerlo.

 

Lo primero de todo será añadir un User Control a nuestro proyecto. En el XAML del control añadiremos los componentes que queremos que se muestren en el popup. Yo para este ejemplo he añadido un texto para el título del mensaje, otro texto para el mensaje, y un botón para que el usuario pueda cerrar el popup:

<UserControl
    x:Class="PopupSample.MessagePopup"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PopupSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"
    SizeChanged="MessagePopup_SizeChanged"
>

    <!-- El contenido de mi control -->
    <Frame Padding="10" Background="DarkCyan">
        <Grid>
            <Grid.RowDefinitions>
                <!-- El ancho del control dependera
 de su contenido -->
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            
            <!-- Titulo del mensaje -->
            <TextBlock 
                Grid.Row="0"
                x:Name="Title"
                HorizontalAlignment="Center" 
                FontSize="28"
                Foreground="White"
                Margin="0, 0, 0, 0"/>
            
            <!-- El mensaje -->
            <TextBlock 
                Grid.Row="1"
                x:Name="Message"
                HorizontalAlignment="Center" 
                FontSize="18" 
                Foreground="White"
                Margin="0, 5, 0, 5"/>
            
            <!-- El boton para cerrarlo -->
            <Button 
                Grid.Row="2" 
                x:Name="DismissButton" 
                BorderBrush="White" 
                FontSize="18" 
                HorizontalAlignment="Center"
                Click="DismissButton_Click"/>
        </Grid>
    </Frame>

</UserControl>

 

Si te fijas en el XAML también le he dado formato al contenido, poniéndolo dentro de un grid con una distribución determinada, dejando los márgenes adecuados, poniendo el color de fondo que me ha gustado, el color del texto, bordes, etc.

También he indicado que habrá un método MessagePopup_SizeChanged al que se llamará cuando el tamaño del control cambie (y eso pasará en cuanto le asigne un texto a los componentes del control) y que me ayudará a situar el popup en pantalla, y un método DismissButton_Click al que se llamará cuando el usuario pulse el botón y que utilizaré para cerrar el popup.

Antes de ver el código detrás de ese XAML te comento lo siguiente:

- Este popup de ejemplo puede cerrarse bien mediante el botón, o bien mediante un temporizador. Te pongo las dos maneras para que puedas elegir la que mejor se adapte a tus necesidades. También podrías añadir de manera muy sencilla un método para que se cierre por código al terminar alguna operación.

- En lugar de pasarle coordenadas al popup para que se pinte en cualquier sitio, este popup de ejemplo se pinta siempre en la esquina superior izquierda, siempre a la misma distancia de la parte de arriba y de la parte derecha de la pantalla: 10 píxeles.

Y aquí tienes el código:

// Control con los elementos a mostrar en el popup
public sealed partial class MessagePopup : UserControl
{
    // Popup que contendrá nuestro control
    private static Popup m_popup = new Popup();

    // Temporizador
    private static ThreadPoolTimer m_timer = null;

    // Inicialización del control
    public MessagePopup()
    {
        this.InitializeComponent();
    }

    // Mostrar el popup
    private static void Show(
        string titleText, string messageText, string dismissButtonText, 
        int milliseconds)
    {
        // Cancelamos el temporizador si lo hay
        if (MessagePopup.m_timer != null)
        {
            MessagePopup.m_timer.Cancel();
        }

        // Creamos el control
        MessagePopup userControl = new MessagePopup();

        if (titleText != null)
        {
            // Ponemos el titulo
            userControl.Title.Text = titleText;
        }
        else
        {
            // Si no hay titulo lo escondemos
            userControl.Title.Visibility = Visibility.Collapsed;
        }

        // Ponemos el mensaje
        userControl.Message.Text = messageText;

        if (dismissButtonText != null)
        {
            // Ponemos el texto del botón
            userControl.DismissButton.Content = dismissButtonText;

            // Si hay botón no queremos temporizador
            MessagePopup.m_timer = null;
        }
        else 
        {
            // Si no hay botón lo escondemos
            userControl.DismissButton.Visibility = Visibility.Collapsed;

            // Ponemos el temporizador en marcha
            MessagePopup.m_timer = ThreadPoolTimer.CreateTimer(

                // Definimos el método que se llamará al terminar
                // el temporizador
                timerElapsedHandler =>
                {
                    // El temporizador ejecuta este metodo en
                    // otro hilo. Utilizamos el dispatcher para
                    // poder actualizar el popup en su propio hilo
                    MessagePopup.m_popup.Dispatcher.RunAsync(
                        Windows.UI.Core.CoreDispatcherPriority.Normal, 

                        // Metodo que va a llamar el dispatcher
                        () =>
                        {
                            // Escondemos el popup
                            MessagePopup.m_popup.IsOpen = false;
                        }).AsTask().Wait();
                }, 
                TimeSpan.FromMilliseconds(milliseconds));
        }

        // Ponemos el control dentro del popup
        MessagePopup.m_popup.Child = userControl;

        // Mostramos el popup
        MessagePopup.m_popup.IsOpen = true;
    }

    // Mostrar un mensaje sin botón durante un tiempo predeterminado
    public static void Show(string messageText)
    {
        MessagePopup.Show(null, messageText, null, 7000);
    }

    // Mostrar un mensaje con su titulo y un botón para cerrarlo
    public static void Show(
        string titleText, string messageText, string dismissButtonText)
    {
        MessagePopup.Show(titleText, messageText, dismissButtonText, 0);
    }

    // Cerrar el popup al pulsar el botón
    private void DismissButton_Click(object sender, RoutedEventArgs e)
    {
        MessagePopup.m_popup.IsOpen = false;
    }

    // Mostrar el popup en la esquina superior izquierda, 
    // a 10 pixeles de la parte de arriba, y a 10 píxeles de la 
    // parte izquierda.
    // Hasta que no sabemos el tamaño final del control, no podemos
    // saber dónde situar el popup exáctamente
    private void MessagePopup_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        // Calculamos la posición del popup según el tamaño de
        // su contenido
        MessagePopup.m_popup.VerticalOffset = 10;
        MessagePopup.m_popup.HorizontalOffset = 
            Window.Current.Bounds.Width - this.ActualWidth - 10;
    }
}

 

Cosas que yo destacaría de este código:

- El popup no es más que el contenedor de nuestro control. Lo que sea que le asignemos, eso mostrará en pantalla.

- Sólo dejo que haya un popup de esta clase en pantalla, por eso declaro m_popup como una propiedad de clase (static). Eso aplica también al temporizador m_timer.

- Asigno la propiedad HorizontalOffset del popup en MessagePopup_SizeChanged, porque hasta que no se lanza ese evento no sé cual es el tamaño exacto de mi control. En el método Show el valor de this.ActualWidth no es válido, por ejemplo.

- Para poder actualizar el estado del popup con el método al que llama el timer, he tenido que utilizar el dispatcher del popup. Puedes encontrar más detalles sobre esto en Windows 8 Tips & Tricks. Modificar la interfaz desde un hilo secundario (XAML/C#)

 

Una vez visto todo esto, cada vez que queramos mostrar el popup con nuestro mensaje, haremos llamadas como las siguientes:

MessagePopup.Show("Este mensaje desaparecerá en 7 segundos");

MessagePopup.Show("Información", "Pulsa el botón", "Cerrar");

 

Si tienes alguna duda, recuerda que tienes a tu disposición el foro de desarrollo de aplicaciones para Windows 8 en castellano, donde podrás compartir tus conocimientos con la comunidad de desarrolladores y encontrar ayuda para resolver tus dudas técnicas, y una Introducción al desarrollo de aplicaciones para Windows 8.

También puedes estar al día de todas las novedades a través de nuestros rincones en las redes sociales:

Un saludo,

      Alejandro Campos Magencio

Blog: formulario de comentarios de publicación (CAPTCHA)