Icono del sitio Programando a medianoche

Ventanas modales en Silverlight

En Silverlight, como es sabido, no se pueden crear ventanas modales, por lo cual vamos a mostrar como simular esta funcionalidad utilizando un Popup.

El Popup es un objeto del framework de Silverlight 2 que permite mostrar el contenido de un elemento sobre el resto. Con esto podríamos simular la ventana que queremos crear, pero tenemos el problema que alrededor de esta ventana se puede cliquear e interactuar con los elementos que están «por debajo» de ésta. Para evitar esto lo que haremos es crear un elemento «Border» que ocupe toda la página de Silverlight, el cual debe tener un fondo para evitar que el usuario pulse sobre los elementos que están por debajo. Para el fondo podemos utilizar, por ejemplo, el objeto SolidColorBrush con el color negro y una opacidad de 20, para que se pueda ver a través él (si no queremos que se grisee esta zona se puede utilizar el color Colors.Transparent).

El siguiente inconveniente que si el control de Silverlight ocupa un porcentaje de la ventana del navegador (o sea, no tiene un tamaño fijo) y el usuario modifica el tamaño del browser, la sección griseada de la ventana debería modificarse para seguir ocupando el cien por ciento de la página. Para solucionar esto se puede manejar el evento Resized del objeto Application.Current.Host.Content, estableciendo ahí el tamaño del borde del Popup al tamaño actual del objeto Application.Current.RootVisual.

Por último, también tenemos el problema de que, si al Popup le agregamos elementos como un ListBox que tiene interacción con el usuario y necesitamos manejar sus eventos, el Silverlight nos devolverá un error. Para evitar esto simplemente tenemos que agregar el Popup al elemento raíz de nuestra página y, al cerrarlo, quitarlo.

A continuación muestro el código de un método estático

/// <summary>
/// Muestra un objeto en una ventana modal simulada a través de un <see cref="Popup"/>
/// </summary>
/// <param name="Content">Contenido a mostrar en la ventana</param>
public static Popup Show(UIElement Content)
{
    //Botón "cerrar"
    Button btnClose = new Button();
    btnClose.Content = new TextBlock() { Text = "Cerrar" };
    btnClose.HorizontalAlignment = HorizontalAlignment.Center;
    btnClose.Margin = new Thickness(0, 10, 0, 0);

    //Grilla para ubicar el contenido y el botón
    Grid objGridContent = new Grid();
    objGridContent.RowDefinitions.Add(new RowDefinition());
    objGridContent.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    objGridContent.Children.Add(Content);
    objGridContent.Children.Add(btnClose);
    Grid.SetRow(btnClose, 1);

    //Borde de la ventana
    Border objPopupBorder = new Border();
    objPopupBorder.CornerRadius = new CornerRadius(10);
    objPopupBorder.Background = new SolidColorBrush(Colors.White);
    objPopupBorder.BorderThickness = new Thickness(2);
    objPopupBorder.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 128, 128, 128));
    objPopupBorder.Child = objGridContent;
    objPopupBorder.Padding = new Thickness(10);
    objPopupBorder.Margin = new Thickness(20);
    objPopupBorder.HorizontalAlignment = HorizontalAlignment.Center;
    objPopupBorder.VerticalAlignment = VerticalAlignment.Center;

    //Fondo de la ventana
    Border objBackBorder = new Border();
    objBackBorder.Width = Application.Current.RootVisual.RenderSize.Width;
    objBackBorder.Height = Application.Current.RootVisual.RenderSize.Height;
    objBackBorder.Background = new SolidColorBrush(Color.FromArgb(70, 0, 0, 0));
    objBackBorder.Opacity = 1;
    objBackBorder.Child = objPopupBorder;

    //Popup
    Popup objPopup = new Popup();
    objPopup.Child = objBackBorder;
    ((Application.Current.RootVisual as UserControl).FindName("LayoutRoot") as Grid).Children.Add(objPopup);
    objPopup.Closed += delegate(object sender, EventArgs e)
    {
        //Saco el popup de la grilla
        UIElementCollection objRootElements = ((Application.Current.RootVisual as UserControl).FindName("LayoutRoot") as Grid).Children;
        if (objRootElements.Contains(objPopup))
            objRootElements.Remove(objPopup);
    };
    objPopup.IsOpen = true;

    //Cerramos el popup al pulsar en el botón
    btnClose.Click += delegate(object sender2, RoutedEventArgs e2) { objPopup.IsOpen = false; };

    //Cambio el tamaño del fondo cuando cambia de tamaño el control
    Application.Current.Host.Content.Resized += delegate(object sender, EventArgs e)
    {
        objBackBorder.Width = Application.Current.RootVisual.RenderSize.Width;
        objBackBorder.Height = Application.Current.RootVisual.RenderSize.Height;
    };

    return objPopup;
}

Como siempre, les dejo un proyecto con este código funcionando para que lo prueben.

Salir de la versión móvil