February 2008 - Artículos

En un artículo anterior realizamos una introducción al control Media de ASP.NET Futures, donde vimos lo simple que resultaba crear un sencillo -pero efectivo-reproductor de audio y/o video utilizando dicho control.

Gracias a su propiedad MediaSkin, podemos seleccionar la carátula o skin que actuará como interfaz de usuario; y aunque el conjunto de carátulas disponibles resulta suficiente para los escenarios de ejecución más comunes, este control nos permite llegar un poco más lejos, al proporcionarnos la posibilidad de manipular cualquiera de los skins de que dispone, para darles un toque más personal.

Tomemos como ejemplo una página a la que hemos añadido un control Media, estableciendo el valor AudioGray como skin. El primer paso a dar para efectuar la personalización de dicho skin pasa por hacer clic en la etiqueta inteligente de este control, seleccionando la opción "Configure skin".

Esta acción producirá la apertura de un cuadro de diálogo, que nos permitirá exportar el skin en formato XAML a un archivo externo.

Una vez exportado el skin a un archivo, que llamaremos por ejemplo AudioGray.xaml, lo editaremos para alterar su apariencia. Dicho proceso de edición podemos llevarlo a cabo utilizando el editor XAML de Visual Studio, pero resulta mucho más recomendable emplear una herramienta como Expression Blend, ya que facilitará en gran medida nuestra labor, al permitirnos modificar visualmente las propiedades de los diversos elementos del skin, evitándonos tener que trabajar directamente con el código XAML.

Después de abrir el archivo del skin en Expression Blend, desde el panel "Objects and Timeline" iremos navegando por su estructura de elementos. Cada vez que seleccionemos uno, nos situaremos en el panel "Properties", modificando su color en el apartado "Brushes", como vemos en la siguiente imagen.

Terminadas las modificaciones, grabaremos el archivo con el nombre AudioColorines.xaml. Para utilizarlo como nuevo skin lo asignaremos a la propiedad XamlUrl del control Media.

<asp:Media ID="medReproductor" runat="server" Height="35px" MediaSkin="AudioGray"
    MediaUrl="GardenParty.mp3" Width="320px" XamlUrl="~/AudioColorines.xaml"/>

El control, una vez aplicado nuestro skin personalizado, mostrará el siguiente aspecto.

Como podemos ver, cambiar la apariencia de este control se convierte en una operación muy sencilla de realizar.

El proyecto con el código fuente de este ejemplo puede descargarse desde el siguiente enlace.

Un saludo.

A raíz de la publicación hace unos días de un artículo sobre el control Media de ASP.NET Futures, me preguntaron acerca de la posibilidad de añadir al blog un post en el que se hiciera un pequeño resumen de los enlaces que sería necesario descargar.

Así que haciendo un pequeño recuento de los diversos productos, utilidades, documentación, etc., he preparado una pequeña lista, que espero pueda ser de utilidad para todos aquellos que quieran "arrancar" con Silverlight y tecnologías afines a esta.

 

Visual Studio

Como entorno de desarrollo integrado (IDE), lo más recomendable es utilizar Visual Studio 2008, cuya versión definitiva -en sus diversas ediciones Professional, Standard, Team System- está casi recién salida del horno. Adicionalmente tenemos también las variantes Express y Visual Web Developer.

Para desarrollar interfaces de usuario basadas en WPF -güepef para los amigos ;-)- es una estupenda opción, ya que WPF-XAML viene integrado en la propia plataforma .NET Framework 3.0 y superiores, y esta se incluye durante el proceso de instalación de Visual Studio. En el caso de utilizar Windows Vista como S.O., .NET Framework 3.0 ya viene instalado "de fábrica", pero no obstante con Visual Studio 2008 obtenemos la versión más reciente -3.5- de la plataforma.

En lo que respecta a la creación de aplicaciones ASP.NET AJAX ocurre algo similar, puesto que las extensiones necesarias para dotar a nuestras páginas Web de características AJAX, utilizando componentes tales como ScriptManager, UpdatePanel, etc., ya vienen incluidas en Visual Studio 2008.

Podemos acceder a la información y descargas relacionadas con Visual Studio y sus variantes a través del siguiente enlace.

http://msdn2.microsoft.com/en-us/vstudio/products/default.aspx

En el apartado de desarrollo con ASP.NET, se encuentra igualmente disponible un hotfix que fundamentalmente aporta una mayor velocidad al diseñador de páginas Web. En este enlace es posible descargar este componente.

https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=10826

Mientras que en el blog de José Manuel Alarcón, existe un post con información adicional sobre el hotfix

http://geeks.ms/blogs/jalarcon/archive/2008/02/09/hotfix-para-desarrollo-web-con-visual-studio-2008.aspx

 

Silverlight

Para que un usuario pueda ejecutar en su navegador contenido Silverlight necesita el runtime o motor de ejecución. La gran mayoría de las páginas que contienen capacidades Silverlight ofrecen un enlace para descargar este runtime, que dependiendo de la versión con la que vayamos a trabajar, también podemos obtener en las siguientes direcciones.

Silverlight 1.0

http://www.microsoft.com/silverlight/downloads.aspx#4_0

Silverlight 2.0 Beta 1

http://www.microsoft.com/silverlight/resources/InstallationFiles.aspx?v=2.0

Debemos recordar que para poner aplicaciones en producción hay que utilizar la versión 1.0, ya que la versión 2.0 está actualmente en Beta 1 y solamente debe utilizarse para pruebas.

En el caso de que vayamos a desarrollar una aplicación en cuyas páginas incluyamos características Silverlight, necesitaremos el SDK de la versión correspondiente, que podemos descargar en estos enlaces.

Silverlight 1.0

http://www.microsoft.com/downloads/details.aspx?FamilyId=FB7900DB-4380-4B0F-BB95-0BAEC714EE17&displaylang=en

Silverlight 2.0 Beta 1

http://www.microsoft.com/downloads/details.aspx?familyid=4E03409A-77F3-413F-B108-1243C243C4FE&displaylang=en

Para la reciente versión 2.0 Beta 1 existe un conjunto de utilidades encaminadas a mejorar la experiencia de desarrollo de este tipo de aplicaciones en VS2008, denominadas "Silverlight 2.0 Tools Beta 1 for Visual Studio 2008", disponibles en este enlace.

http://www.microsoft.com/downloads/details.aspx?FamilyID=e0bae58e-9c0b-4090-a1db-f134d9f095fd&DisplayLang=en#top

 

ASP.NET Futures

Este paquete de componentes proporciona un conjunto de funcionalidades avanzadas para ASP.NET, algunas de ellas aplicables a Silverlight, como el control Media.

http://www.microsoft.com/downloads/details.aspx?FamilyId=A5189BCB-EF81-4C12-9733-E294D13A58E6&displaylang=en

 

Expression Blend

A la hora de elaborar la interfaz de usuario WPF podemos escribir "a mano" el código XAML correspondiente, pero en cuanto dicha interfaz comience a complicarse, es mejor recurrir a una aplicación como Expression Blend, que permite realizar visualmente el diseño de la interfaz, generando el XAML correspondiente, lo cual facilita enormemente nuestro trabajo. El siguiente enlace ofrece la posibilidad de descargar la preview de diciembre de este producto, la cual ofrece un gran nivel de integración para desarrollar con Silverlight.

http://www.microsoft.com/Expression/products/download.aspx?key=blend2preview

Pero si queremos obtener soporte mejorado para Silverlight 2.0, también tenemos disponible Expression Blend Preview 2.5, de marzo de 2008.

http://www.microsoft.com/expression/products/download.aspx?key=blend2dot5

 

Ajax Control Toolkit

Si vamos a utilizar en gran medida AJAX dentro de nuestras aplicaciones, el Ajax Control Toolkit resultará un recurso de inestimable ayuda, puesto que proporciona un conjunto de controles y extensores para dar a las páginas el toque especial de AJAX. El archivo conteniendo los controles para la versión 3.5 de .NET Framework -AjaxControlToolkit-Framework3.5.zip- se puede obtener en esta dirección.

http://www.codeplex.com/AtlasControlToolkit/Release/ProjectReleases.aspx?ReleaseId=8513

Y un interesante video, con el nombre "ASP.NET AJAX Support in Visual Studio 2008" conteniendo explicaciones sobre el soporte para AJAX integrado en Visual Studio 2008, así como los pasos de instalación del Ajax Control Toolkit puede descargarse en este enlace.

http://www.asp.net/ajax/

Como pequeño botón de muestra, en este otro enlace disponemos de un post que publiqué en este mismo blog acerca del uso de uno de los extensores incluidos en el Ajax Control Toolkit.

 

Recursos de documentación

En lo que respecta a este apartado sobre documentación, ejemplos, centro de descargas, etc., la página principal de Silverlight supone uno de los puntos de entrada que no deben faltar en nuestros favoritos.

http://silverlight.net/

También en Geeks existen muchos compañeros que tratan sobre este tema, los siguientes enlaces correspondientes a Sergio Tarrillo y Eugenio Estrada Csaky son una buena muestra de toda la interesante información que podemos encontrar aquí.

http://geeks.ms/blogs/sergiotarrillo/archive/tags/ASP.NET+AJAX/default.aspx

http://geeks.ms/blogs/eecsaky/archive/2007/04/30/silverlight-1-0-beta-y-1-1-alpha-asp-net-futures-y-blend-2-las-novedades-de-mayo.aspx

Por supuesto que tampoco puede faltar el blog de uno de los principales evangelistas de Silverlight: Jesse Liberty.

http://silverlight.net/blogs/jesseliberty/default.aspx

Y de Adam Nathan, autor de dos de los libros más importantes sobre WPF y Silverlight: "Windows Presentation Foundation Unleashed" y "Silverlight 1.0 Unleashed".

http://blogs.msdn.com/adam_nathan/

Comentando acerca de este post con mi buen amigo Marino Posadas, me ha sugerido un par de estupendos enlaces adicionales. Así que como colaboración de lujo aquí van. Muchas gracias Marino!!! 8-D.

El primero de ellos sería un sitio en el que podemos descargar algunos ebooks gratuitos sobre estas tecnologías.

http://www.buayacorp.com/archivos/ebooks-gratuitos-linq-aspnet-ajax-silverlight/

Mientras que el segundo se trata del blog de otro gran evangelista. Laurence Moroney.

http://wldj.sys-con.com/author/2241moroney.htm

 

VirtualPC

Aunque no sea imprescindible, puede resultar de mucha utilidad el empleo de una máquina virtual en donde testear todos estos productos. Si preferimos crear un entorno de desarrollo de prueba separado de la configuración de trabajo habitual, con VirtualPC podemos montar una máquina virtual donde hacer todas estas "trastadas", sin afectar a nuestra configuración normal de trabajo.

http://www.microsoft.com/downloads/details.aspx?FamilyId=04D26402-3199-48A3-AFA2-2DC0B40A73B6&displaylang=en

Bien, pues esto sería todo. Como se suele decir, no están todos los que son, pero sí son todos los que están ;-). Espero que os pueda servir de utilidad.

Un saludo.

Entre las características predeterminadas del control DataGridView de Windows Forms, se encuentra la visualización de las líneas de separación que delimitan las celdas que componen la cuadrícula de datos.

Si por alguna circunstancia no deseamos que dichas líneas se muestren al usuario, podemos utilizar la propiedad CellBorderStyle, asignándole el valor None de la enumeración DataGridViewCellBorderStyle, la cual nos permite también aplicar diversos efectos de resaltado de estas líneas.

this.dataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.None;

La siguiente imagen muestra el control después de haber ocultado sus líneas.

Pero siendo un poco más rebuscados, supongamos que queremos eliminar estas líneas de una forma selectiva, por ejemplo, la línea vertical que separa las dos primeras columnas. En este caso, la propiedad CellBorderStyle no resulta de ayuda, por lo que tendremos que recurrir a una técnica un poco más compleja, basada en realizar el dibujo de todos los elementos de la celda manualmente mediante el evento CellPainting del DataGridView.

Como podemos adivinar por su nombre, CellPainting es un evento que se desencadenará cada vez que el control necesite pintar una celda, por lo que resulta el punto idóneo para personalizar el modo en cómo queremos que se muestre el dato contenido en la celda al usuario.

El procedimiento a seguir para realizar el dibujo personalizado de una celda consiste en comprobar en primer lugar si estamos ante la fila y columna que necesitamos. A continuación también observaremos si la celda está seleccionada, ya que en ese caso tendremos que utilizar una combinación de colores distinta para resaltar el contenido.

Seguidamente dibujamos el rectángulo correspondiente a la celda, cuyas dimensiones obtenemos de la propiedad CellBounds, perteneciente al parámetro DataGridViewCellPaintingEventArgs que recibe este evento, rellenándolo con el color de fondo que corresponda: seleccionado o normal. Para que la combinación de colores se ajuste a la utilizada por los controles estándar, emplearemos los colores obtenidos a partir de las propiedades públicas pertenecientes a la clase SystemColors.

En el siguiente paso dibujaremos únicamente la línea vertical de separación para las filas de la celda.  En el caso de que la celda tenga un valor que mostrar, lo dibujaremos mediante el método estático DrawText de la clase TextRenderer, pasando, entre otros valores, el tipo de letra que obtenemos del estilo correspondiente a la celda, el rectángulo sobre el que se dibujará el texto que nos proporciona el parámetro DataGridViewCellPaintingEventArgs. CellBounds, y el color que hemos establecido anteriormente tras comprobar si la celda estaba o no seleccionada.

Dado que estamos pintando de modo personalizado la celda, terminaremos el código del manipulador de este evento indicando dicha circunstancia -asignando el valor true a la propiedad DataGridViewCellPaintingEventArgs.Handled-,  para así evitar que el control intente realizar alguna acción de dibujo sobre la celda por su cuenta. El código fuente necesario podemos verlo a continuación.

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    // comprobar que la fila y columna son las adecuadas
    if (e.RowIndex >= 0 && (e.ColumnIndex == 0))
    {
        Color clrFondoCelda;
        Color clrTextoCelda;
        // en función de si la celda está o no seleccionada
        // establecer los colores
        if ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected)
        {
            clrFondoCelda = SystemColors.Highlight;
            clrTextoCelda = SystemColors.Window;
        }
        else
        {
            clrFondoCelda = SystemColors.Window;
            clrTextoCelda = SystemColors.WindowText;
        }

        // rellenar el rectángulo de la celda con el color correspondiente
        e.Graphics.FillRectangle(new SolidBrush(clrFondoCelda), e.CellBounds);

        // dibujar solamente la línea vertical de la celda
        e.Graphics.DrawLine(new Pen(SystemColors.ActiveBorder),
            new Point(e.CellBounds.X, e.CellBounds.Y + e.CellBounds.Height - 1),
            new Point(e.CellBounds.X + e.CellBounds.Width, e.CellBounds.Y + e.CellBounds.Height - 1));

        // si la celda tiene valor
        if (e.Value != null)
        {
            // dibujar el texto
            TextRenderer.DrawText(e.Graphics,
                e.FormattedValue.ToString(),
                e.CellStyle.Font,
                e.CellBounds,
                clrTextoCelda);
        }

        e.Handled = true;
    }
}

El efecto de la eliminación de esta línea en las celdas podemos apreciarlo en la siguiente imagen.

Observemos un efecto curioso: el texto de la celda que hemos dibujado mediante CellPainting ha quedado alineado en el centro, cuando por defecto queda a la izquierda. Si queremos que dicha alineación permanezca en el lugar original, hemos de añadir un parámetro adicional al método TextRenderer.DrawText. Dicho parámetro es un valor de la enumeración TextFormatFlags, que nos permite aplicar este y otro tipo de efectos al texto que dibujemos manualmente.

TextRenderer.DrawText(e.Graphics,
    e.FormattedValue.ToString(),
    e.CellStyle.Font,
    e.CellBounds,
    clrTextoCelda,
    TextFormatFlags.Left);

Ahora las celdas de esta columna ya se mostrarán con la alineación correcta.

El código fuente de este ejemplo puede descargarse en estos enlaces para C# y VB.

Un saludo.

Publicado por Luis Miguel Blanco | 7 comment(s)
Archivado en: ,

Después del artículo de introducción al control Media de ASP.NET Futures, he seguido investigando un poco con este control y he descubierto una característica muy interesante, consistente en la posibilidad de definir marcadores o capítulos para puntos de tiempo asociados a la reproducción, los cuales nos permitirán durante la ejecución, saltar directamente a los momentos que hayamos definido.

Un capítulo se compone de una imagen y un momento de tiempo. El conjunto de capítulos que asociemos a un control Media se denomina menú de capítulos, y se visualizará en forma de tira de imágenes encima de la zona de reproducción de video. El lugar preciso en el que se mostrará el menú de capítulos depende del skin empleado.

Para crear un capítulo dentro del código aspx de la página utilizaremos la etiqueta MediaChapter, asignando la imagen correspondiente al capítulo mediante la propiedad ImageUrl. Para el salto de tiempo usaremos la propiedad TimeIndex, asignando un valor en formato de segundos. Adicionalmente podemos dar un nombre al capítulo mediante su propiedad Title, y por último situaremos todos los MediaChapter dentro de las etiquetas Chapters del control Media, como vemos en el siguiente bloque de código.

<cc1:Media ID="medReproductor" runat="server" Width="400px" Height="325px" MediaUrl="Kameo.wmv"
    MediaSkin="Professional" AutoPlay="True">
    <Chapters>
        <cc1:MediaChapter ImageUrl="Capitulo1.jpg" TimeIndex="12.0" Title="Capítulo 1" />
        <cc1:MediaChapter ImageUrl="Capitulo2.jpg" TimeIndex="36.0" Title="Capítulo 2" />
        <cc1:MediaChapter ImageUrl="Capitulo3.jpg" TimeIndex="65.0" Title="Capítulo 3" />
        <cc1:MediaChapter ImageUrl="Capitulo4.jpg" TimeIndex="73.0" Title="Capítulo 4" />
    </Chapters>
</cc1:Media>

Si resulta más conveniente, también podemos agregar los capítulos desde el code-behind de la página, empleando la clase MediaChapter y la colección Chapters del control.

this.medReproductor.Chapters.Add(new MediaChapter("Capitulo 1", 12.0, "Capitulo1.jpg"));
this.medReproductor.Chapters.Add(new MediaChapter("Capitulo 2", 36.0, "Capitulo2.jpg"));
this.medReproductor.Chapters.Add(new MediaChapter("Capitulo 3", 65.0, "Capitulo3.jpg"));
this.medReproductor.Chapters.Add(new MediaChapter("Capitulo 4", 73.0, "Capitulo4.jpg"));

El resultado en tiempo de ejecución podemos apreciarlo en la siguiente imagen, donde el control Media utiliza el skin Professional, que visualiza el menú de capítulos al situar el cursor en la parte inferior de la zona de video.

En otros tipos de skin se proporciona un botón para desplegar el menú de capítulos, como los que podemos ver a continuación.

El proyecto correspondiente a este ejemplo puede descargarse en este enlace.

 

Reproducir audio combinado con imágenes.

Pero supongamos que en lugar de video, lo que necesitamos es reproducir un archivo de audio, con la particularidad de que durante la reproducción, el usuario debe ir visualizando un conjunto de imágenes.

Podemos utilizar el control Media y asignar las imágenes como capítulos, sin embargo, el usuario solamente podrá ver dichas imágenes en el menú de capítulos, mientras que lo que realmente sería deseable es que se visualizaran en el panel de video del control.

Para resolver este problema, una posible solución sería recurrir a Windows Movie Maker, una aplicación que en Windows Vista viene incorporada por defecto, mientras que en Windows XP puede ser descargada como actualización.

Mediante Windows Movie Maker podemos crear un proyecto donde combinemos el archivo de audio junto a las imágenes, indicando los momentos de la reproducción en los que se realizará una transición de imágenes. A continuación vemos la interfaz de usuario de esta aplicación.

Una vez creada la combinación de imágenes y audio, seleccionaremos la opción de publicación en el equipo local, para generar un archivo wmv que será el que utilicemos con el control Media.

<cc1:Media ID="medReproductor" runat="server" Width="320px" Height="240px" 
    MediaUrl="SonidoDiapositivas.wmv"
    MediaSkin="Expression" AutoPlay="True" />

Al reproducir ahora este archivo desde nuestra página, en el fondo del control Media se irá produciendo la transición de imágenes esperada.

Un saludo.

Supongamos que durante el desarrollo de una aplicación ASP.NET, uno de los requerimientos consiste en implementar un sencillo reproductor de archivos de audio. Se trata de una tarea que podríamos solventar recurriendo al uso de alguno de los variados productos de terceros fabricantes que existen en el mercado, pero como hemos comentado, el reproductor a integrar en nuestro programa no precisa de características complejas, basta con que disponga de los controles básicos tales como reproducir, pausa, parada, etc., por lo que quizá sería un gasto que podríamos evitar si desarrollamos un pequeño control reproductor de "andar por casa".

Si estamos creando nuestra aplicación utilizando Visual Studio 2008 / 2005, podemos utilizar las capacidades multimedia que nos brinda Silverlight para incorporar esta característica. Pero puede que todavía no seamos muy diestros en el uso de Silverlight, y asumiendo que estamos utilizando la versión 1.0, la pelea a brazo partido con Javascript, el elemento MediaElement de XAML, y otros elementos necesarios de este lenguaje de marcado, podría convertirse en una batalla muy dura si disponemos de poco tiempo para completar este aspecto de la aplicación. Pero no desesperemos, que no está todo perdido, al rescate llegan los ASP.NET Futures.

ASP.NET Futures, como ya han comentado en sus respectivos blogs Jorge Serrano, Eugenio Estrada Csaky, Sergio Tarrillo y otros compañeros de Geeks, se trata de un paquete de componentes y controles que aportan un numeroso conjunto de funcionalidades para el desarrollo de aplicaciones ASP.NET y Silverlight. Para el problema en concreto ante el que nos enfrentamos, la versión de julio de 2007 de ASP.NET Futures nos ofrece el control Media, que consiste en un reproductor de archivos de audio y video con las funcionalidades básicas que le pediríamos a cualquier componente de estas características. Este control se encuentra accesible en la Caja de herramientas de Visual Studio como vemos en la siguiente imagen.

Poner en funcionamiento un reproductor simple con este control se convierte en una tarea de lo más sencilla: basta con arrastrarlo hasta el diseñador del WebForm y asignar a su propiedad MediaUrl el archivo a reproducir. Adicionalmente podemos asignar el valor True a la propiedad AutoPlay para que la reproducción comience inmediatamente al cargar la página. La siguiente imagen muestra el aspecto por defecto del control en plena ejecución de un video.

Otra cuestión importante a destacar reside en el hecho de que precisamos incluir un componente ScriptManager en nuestra página para que todo se ejecute correctamente, aunque si al crear el proyecto hemos empleado la plantilla "ASP.NET AJAX Futures Web Application", no será necesario ya que esta se encarga de añadirlo.

Un control camaleónico.

Como acabamos de comprobar, para abordar la reproducción de contenido multimedia de forma rápida y fácil, el control Media se convierte en un poderoso aliado, pero como hemos dicho anteriormente, resulta que solamente queremos reproducir audio, por lo que el área reservada por el control para la visualización de video necesitaríamos que quedara oculta, " ¿hay alguna manera de conseguirlo?", pues sí, recurriendo al uso de un skin, que proporcione al control una apariencia más acorde a las funcionalidades que deba desempeñar.

Pero no nos asustemos, ya hemos dicho que Media es un control fácil de usar, y proporciona, a través de su propiedad MediaSkin -que contiene una enumeración MediaSkinType- una colección de carátulas para cambiar su aspecto. En este caso elegiremos el valor AudioGray, correspondiente al skin que mejor se ajusta a nuestras necesidades de reproducción.

La siguiente imagen muestra algunas otras carátulas que ofrece este control.

Un ejemplo más completo. Seleccionando el archivo a reproducir y el skin.

Como parte final de este artículo vamos a desarrollar un pequeño proyecto en Visual Studio 2008, cuyos fuentes pueden descargarse en los siguientes enlaces para C# y VB. Esta aplicación consistirá en proporcionar al usuario una página que contenga un control Media y dos DropDownList, para seleccionar el archivo de audio/video (los cuales no se acompañan junto al proyecto de ejemplo) y el skin respectivamente.

En primer lugar escribiremos el código que vemos a continuación para la interfaz de usuario de la página, empleando un UpdatePanel para evitar recargas completas sobre la misma.

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <table style="width: 58%;" border="1">
                <tr>
                    <td class="style1">
                        <asp:Label ID="Label1" runat="server" Text="Archivos de audio/video" /></td>
                    <td class="style2">
                        <asp:Label ID="Label2" runat="server" Text="Skins" />
                    </td>
                </tr>
                <tr>
                    <td class="style1">
                        <asp:DropDownList ID="ddlArchivos" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddlArchivos_SelectedIndexChanged">
                            <asp:ListItem Value="GardenParty.mp3">Garden Party</asp:ListItem>
                            <asp:ListItem Value="Incubus.mp3">Incubus</asp:ListItem>
                            <asp:ListItem Value="MarketSquareHeroes.mp3">Market Square Heroes</asp:ListItem>
                            <asp:ListItem Value="Kameo.wmv">Kameo</asp:ListItem>
                        </asp:DropDownList>
                    </td>
                    <td class="style2">
                        <asp:DropDownList ID="ddlSkins" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddlSkins_SelectedIndexChanged" />
                    </td>
                </tr>
            </table>
            <br />
            <asp:Media ID="medReproductor" runat="server" Width="320px" Height="240px" />
        </ContentTemplate>
    </asp:UpdatePanel>
</div>
</form>

Posteriormente pasaremos al code-behind, donde escribiremos la lógica encargada de seleccionar el archivo a reproducir, y el skin que utilizará el control Media para mostrar su aspecto. Nótese que para rellenar el control DropDownList correspondiente a los nombres de los skins, dado que dichos nombres se encuentran en el tipo enumerado MediaSkinType, empleamos el método Enum.GetNames para obtener un array que posteriormente enlazamos al control de lista.

//....
using Microsoft.Web.Preview.UI.Controls;
using System.Text;
//....
protected void Page_Load(object sender, EventArgs e)
{
    if (!this.IsPostBack)
    {
        // obtener la lista de nombres de la enumeración
        // y asignarla a la lista desplegable correspondiente
        string[] aNombresSkin = Enum.GetNames(typeof(MediaSkinType));
        this.ddlSkins.DataSource = aNombresSkin;
        this.ddlSkins.DataBind();
        
        // reproducir el primer archivo de la lista
        this.medReproductor.AutoPlay = true;
        this.medReproductor.MediaUrl = this.ddlArchivos.SelectedValue;                
    }
}

protected void ddlSkins_SelectedIndexChanged(object sender, EventArgs e)
{
    // cambiar el skin del reproductor
    this.medReproductor.MediaSkin =
        (MediaSkinType)Enum.Parse(typeof(MediaSkinType), this.ddlSkins.SelectedValue);
}

protected void ddlArchivos_SelectedIndexChanged(object sender, EventArgs e)
{
    // reproducir un nuevo archivo
    this.medReproductor.MediaUrl = this.ddlArchivos.SelectedValue;
}

Una vez concluida la escritura del code-behind, ejecutaremos la aplicación que mostrará un aspecto como el siguiente.

Espero que este artículo sea de utilidad para todos aquellos que puedan verse en la necesidad de implementar un sencillo reproductor multimedia utilizando ASP.NET Futures.

Un saludo.

Cuando utilizamos un control DataGridView como medio de presentación de los datos de una consulta, si el texto perteneciente a una columna resulta excesivamente largo, el control se ocupa de recortarlo de modo que en las celdas se visualice una parte del mismo, añadiendo al final unos puntos suspensivos, que indican al usuario la existencia de más texto, el cual puede visualizar si redimensiona el ancho de la columna.

Pero supongamos que es conveniente mantener la anchura de las columnas en nuestro control de cuadrícula, siendo necesario que el texto de la mencionada columna pueda ajustarse dentro de la celda, de tal manera que se reparta en varias filas.

Este comportamiento está disponible a través de una de las propiedades de estilo del DataGridView: WrapMode, a la que si asignamos el valor DataGridViewTriState.True, conseguiremos que el texto se divida en la celda sin necesidad de cambiar el ancho de la misma.

Como ejemplo de lo que estamos comentando, el siguiente código fuente carga un DataGridView con los registros de una tabla. Nótese que en la consulta SQL, se crea un campo calculado, concatenando tres de los existentes en la tabla, de forma que consigamos una columna con una buena cantidad de texto, que nos permita realizar las pruebas más adecuadamente.

private void Form1_Load(object sender, EventArgs e)
{
    SqlConnection cnConexion = new SqlConnection();
    cnConexion.ConnectionString = "Data Source=localhost;" +
        "Initial Catalog=Northwind;" +
        "Integrated Security=True";

    StringBuilder sbSQL = new StringBuilder();
    sbSQL.Append("SELECT CustomerID, ");
    sbSQL.Append("CompanyName + '-' + ContactName + '-' + Address AS DatosCliente, " );
    sbSQL.Append("City, Country FROM Customers");

    SqlCommand cmdComando = new SqlCommand(sbSQL.ToString(), cnConexion);
    SqlDataAdapter daAdaptador = new SqlDataAdapter(cmdComando);

    DataSet dsDatos = new DataSet();
    daAdaptador.Fill(dsDatos, "Customers");

    this.dataGridView1.DataSource = dsDatos;
    this.dataGridView1.DataMember = "Customers";

    this.dataGridView1.DefaultCellStyle.BackColor = Color.LightYellow;
    this.dataGridView1.DefaultCellStyle.ForeColor = Color.DarkViolet;

    // configurar el estilo predeterminado del DataGridView
    // para que divida el texto de las celdas en varias líneas
    this.dataGridView1.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
}

Sin embargo, el código anterior resuelve el problema sólo en parte, puesto que al ejecutar de nuevo la aplicación, no se muestra el texto de la celda al completo. Podemos observar que en efecto, ahora el texto se ha dividido en varias líneas, pero el usuario debe redimensionar la fila para poder ver el contenido al completo de la celda.

Para conseguir que el DataGridView redimensione automáticamente la altura de sus celdas, adaptándose al contenido de las mismas, es necesario ejecutar el método DataGridView.AutoResizeRows, pasándole como parámetro un valor de la enumeración DataGridViewAutoSizeRowsMode, para establecer el modo de ajuste automático.

Dado que esta operación necesitamos realizarla después de que el control haya terminado de cargar los registros del origen de datos, un lugar adecuado sería el evento Paint del control, como vemos a continuación.

private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
    this.dataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.DisplayedCells);
}

Al volver al ejecutar el formulario, las filas del DataGridView adaptarán ahora su altura para mostrar todo el contenido de las celdas sin necesidad de redimensionarlas manualmente.

No obstante, al observar el formulario en ejecución, habremos percibido un efecto de parpadeo, producido por el reajuste continuo que está realizando el control al ejecutar el evento Paint.

Una solución a este problema consistiría en ejecutar el método DataGridView.AutoResizeRows dentro del manipulador del evento Paint solamente una vez, tras la carga inicial de datos del control. Para ello, declararemos una variable con ámbito a nivel de la clase del formulario, que se comporte como un indicador de estado, cambiando su valor tras la primera ejecución de Paint, como vemos en el siguiente bloque de código.

public partial class Form1 : Form { // indicador para ajustar la altura de las celdas // al presentar inicialmente el DataGridView bool blnAjustarCeldas = true; //…. private void dataGridView1_Paint(object sender, PaintEventArgs e) { if (blnAjustarCeldas) { blnAjustarCeldas= false;

this.dataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.DisplayedCells); } } }

Pero todavía no hemos terminado, falta salvar un escollo más, ya que con el ajuste anterior evitamos el efecto de parpadeo, pero al comenzar a desplazarnos por el resto de registros del DataGridView, estas volverán a mostrarse sin el ajuste en su altura. El remedio ahora pasaría por codificar el manipulador del evento Scroll del control, ejecutando también aquí el método DataGridView.AutoResizeRows.

private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
{
    this.dataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.DisplayedCells);
}

Tras este último aderezo en nuestro código, ahora sí que funcionará según el objetivo marcado al principio del artículo.

El código fuente puede descargarse en los siguientes enlaces: C# y VB.

Un saludo.

 

Publicado por Luis Miguel Blanco | 20 comment(s)
Archivado en: ,

A partir de Visual Studio 2005, el diseño de menús para Windows Forms experimentó una mejora considerable gracias a la incorporación de la clase MenuStrip a la plataforma .NET, a la que acompañaban también todo el conjunto de clases relacionadas con ella: ToolStripMenuItem, ToolStripSeparator, ToolStripTextBox, etc., y que incrementaban notablemente las funcionalidades aportadas por la clase dedicada hasta ese momento a tales menesteres: MainMenu.

La creación de un menú utilizando la clase MenuStrip, nos permite definir sus opciones con características que están más allá del mero literal que muestra el título de la opción, siendo posible que su comportamiento sea el de una caja de texto o una lista desplegable.

No obstante, la finalidad del presente artículo no es mostrar las características particulares de tales tipos de opción de menú, sino exponer un ejemplo que nos permita recorrer su estructura de opciones, realizando cambios en las mismas, en función de si pertenecen a un tipo determinado o poseen ciertas características.

Para ello partiremos de un formulario al que añadiremos un menú con el conjunto de opciones que vemos en la siguiente imagen.

Entre las opciones de este menú podemos observar (indicadas con flechas en la imagen) que se encuentran dos de tipo caja de texto -objetos ToolStripTextBox-, mientras que en el resto existen algunas cuyo literal comienza por minúscula. El objetivo del proceso a desarrollar será cambiar a negrita y cursiva el tipo de letra de las opciones situadas en la barra de menú, convertir a mayúscula el contenido de las opciones de tipo ToolStripTextBox, y situar una marca de verificación junto a las opciones que empiezan por minúscula.

Dado que un menú puede organizarse -tal y como vemos en este ejemplo- en opciones que a su vez despliegan nuevos conjuntos de opciones dependientes, se hace necesario implementar un algoritmo recursivo que permita llegar a todos los niveles de submenús existentes en su estructura.

Sin embargo, antes que entrar en la creación de dicho algoritmo, nos ocuparemos de las dos opciones que se encuentran en la barra de menú, cuyo tipo de letra vamos a convertir a negrita y cursiva recorriendo la colección MenuStrip.Items como vemos a continuación. Todas las operaciones de transformación del menú las realizaremos desde el evento Click de un control Button situado en el formulario.

private void btnModificar_Click(object sender, EventArgs e)
{
    // crear un nuevo tipo de letra para las opciones de la barra de menú
    Font fntTipoLetra = new Font(menuStrip1.Items[0].Font.FontFamily,
        menuStrip1.Items[0].Font.Size,
        FontStyle.Bold | FontStyle.Italic);

    // recorrer las opciones del menú
    foreach (ToolStripMenuItem mnuitOpcion in this.menuStrip1.Items)
    {
        // cambiar el tipo de letra
        mnuitOpcion.Font = fntTipoLetra;
    }
}

Después de ejecutar el anterior código habremos realizado la transformación de las opciones de menú de la barra... ¡¡¡y también del resto de opciones!!! =8-O, ya que un cambio de estas características, realizado en la opción principal de la barra, se propaga al resto de opciones del mismo tipo que dicha opción despliega, por lo que las opciones de tipo ToolStripTextBox no se verán afectadas.

Puesto que solamente deseamos modificar el tipo de letra en la barra de menú, guardaremos el objeto Font original en una variable, restaurándolo al recorrer las opciones de los menús desplegables.

En lo que respecta al proceso encargado de recorrer estos menús desplegables, el modo de detectar si una opción de menú tiene un submenú asociado, pasa por comprobar su propiedad DropDownItems, la cual es una colección de objetos ToolStripItem.

private void btnModificar_Click(object sender, EventArgs e)
{
    // obtener el tipo de letra original de las opciones de menú
    // para restaurarlo en las opciones desplegables
    Font fntOriginal = this.menuStrip1.Items[0].Font;
    //....
    // recorrer las opciones del menú
    foreach (ToolStripMenuItem mnuitOpcion in this.menuStrip1.Items)
    {
        //....
        // si esta opción despliega un submenú
        // llamar a un método para hacer cambios
        // en las opciones del submenú
        if (mnuitOpcion.DropDownItems.Count > 0)
        {                    
            this.CambiarOpcionesMenu(mnuitOpcion.DropDownItems, fntOriginal);
        }
    }
}

Para cada opción de menú situada en la barra comprobaremos si despliega un submenú, y en caso afirmativo, llamaremos a un método con el nombre CambiarOpcionesMenu, que será ejecutado recursivamente cada vez que volvamos a encontrarnos con una opción que despliegue nuevos elementos. Este método recibirá como parámetros la colección de opciones a recorrer, y el objeto Font original a restaurar sobre las opciones.

private void CambiarOpcionesMenu(ToolStripItemCollection colOpcionesMenu, Font fntTipoOriginal)
{
    // recorrer el submenú
    foreach (ToolStripItem itmOpcion in colOpcionesMenu)
    {
        //....
        // si esta opción a su vez despliega un nuevo submenú
        // llamar recursivamente a este método para cambiar sus opciones
        if (((ToolStripMenuItem)itmOpcion).DropDownItems.Count > 0)
        {
             this.CambiarOpcionesMenu(((ToolStripMenuItem)itmOpcion).DropDownItems,
                 fntTipoOriginal);
         }
    }
}

Al recorrer la colección ToolStripItemCollection, cada uno de sus elementos es un tipo de la clase base ToolStripItem. Es por ello que deberemos realizar una operación de conversión de tipos, para obtener el tipo de opción adecuado, y aplicarle los cambios pertinentes cuando sea necesario. Seguidamente podemos ver el código fuente del ejemplo al completo.

private void btnModificar_Click(object sender, EventArgs e)
{
    // obtener el tipo de letra original de las opciones de menú
    // para restaurarlo en las opciones desplegables
    Font fntOriginal = this.menuStrip1.Items[0].Font;

    // crear un nuevo tipo de letra para las opciones de la barra de menú
    Font fntTipoLetra = new Font(menuStrip1.Items[0].Font.FontFamily,
        menuStrip1.Items[0].Font.Size,
        FontStyle.Bold | FontStyle.Italic);

    // recorrer las opciones del menú
    foreach (ToolStripMenuItem mnuitOpcion in this.menuStrip1.Items)
    {
        // cambiar el tipo de letra
        mnuitOpcion.Font = fntTipoLetra;

        // si esta opción despliega un submenú
        // llamar a un método para hacer cambios
        // en las opciones del submenú
        if (mnuitOpcion.DropDownItems.Count > 0)
        {
            this.CambiarOpcionesMenu(mnuitOpcion.DropDownItems, fntOriginal);
        }
    }
}

private void CambiarOpcionesMenu(ToolStripItemCollection colOpcionesMenu, Font fntTipoOriginal)
{
    // recorrer el submenú
    foreach (ToolStripItem itmOpcion in colOpcionesMenu)
    {
        // restaurar el tipo de letra original
        itmOpcion.Font = fntTipoOriginal;

        // si la opción de menú es de tipo caja de texto
        // pasar su contenido a mayúsculas
        if (itmOpcion.GetType() == typeof(ToolStripTextBox))
        {
            itmOpcion.Text = itmOpcion.Text.ToUpper();
        }

        // si es una opción de menú normal...
        if (itmOpcion.GetType() == typeof(ToolStripMenuItem))
        {
            // ... y el primer caracter está en minúscula
            // poner en la opción una marca de verificación
            if (char.IsLower(itmOpcion.Text.ToCharArray(0, 1)[0]))
            {
                ((ToolStripMenuItem)itmOpcion).Checked = true;
            }

            // si esta opción a su vez despliega un nuevo submenú
            // llamar recursivamente a este método para cambiar sus opciones
            if (((ToolStripMenuItem)itmOpcion).DropDownItems.Count > 0)
            {
                this.CambiarOpcionesMenu(((ToolStripMenuItem)itmOpcion).DropDownItems,
                    fntTipoOriginal);
            }
        }
    }
}

En la siguiente imagen podemos ver el resultado de ejecutar el anterior código sobre nuestro menú, con el que hemos logrado modificar dinámicamente las propiedades de sus elementos.

Los proyectos de Visual Studio con los fuentes correspondientes a este ejemplo, pueden descargarse en los siguientes enlaces para C# y VB.

Espero que os resulte de utilidad.

Un saludo.

Publicado por Luis Miguel Blanco | 29 comment(s)
Archivado en:

Cuando empezamos a trabajar con el diseñador de informes de Crystal Reports, si necesitamos crear un informe con un buen número de columnas, es muy posible que todas no puedan situarse en la orientación de página -vertical- que por defecto ofrece el diseñador, por lo que necesitaremos cambiarla a horizontal.

Si estamos diseñando nuestro informe desde Visual Studio 2003, nuestra primera intención será, muy posiblemente, buscar en la ventana de propiedades del informe una propiedad relacionada con este particular, o bien, entre las opciones de menú del entorno de desarrollo.

La opción en cuestión para conseguir este efecto no se halla sin embargo accesible de este modo, siendo necesario para ello hacer clic derecho en la superficie del diseñador de informes, eligiendo del menú contextual que aparece seguidamente la opción "Diseñador > Preparar impresora", como vemos en esta imagen.

A continuación se abrirá una caja de diálogo en la que ya sí podremos seleccionar la orientación de página tanto en tiempo de diseño como de ejecución.

A partir de Visual Studio 2005, esta opción de configuración ya se puede localizar un poco más fácilmente, puesto que mientras que nos encontremos situados en el diseñador de informes, en la barra de menú de Visual Studio aparecerá una opción específica para Crystal Reports, como vemos a continuación.

Espero que con estas indicaciones ahorréis un poco de tiempo al intentar localizar esta opción.

Un saludo.

Publicado por Luis Miguel Blanco | 20 comment(s)
Archivado en: ,