Jun 27

Estoy trabajando con un MasterPage, el cual tiene un campo de texto y un ImageButton para efectuar una búsqueda en el sitio web.

Tengo una página de Inicio de Sesión, la cual está basada en el MasterPage. Cuando tecleó nombre de usuario y contraseña, y oprimo Enter, en lugar de enviarse el formulario del login, se envía el formulario del MasterPage porque toma precedencia sobre el formulario del login.

Después de investigar en Google, llegué al siguiente código:

El control de Login no tiene nada de especial:

ASP:
  1. <asp:Content ID="Content1" ContentPlaceHolderID="Cuerpo" Runat="Server">
  2.  
  3.     <asp:Login ID="Login1" runat="server" DisplayRememberMe="False" FailureText="Datos incorrectos, inténtelo nuevamente."
  4.         LoginButtonText="Entrar" PasswordLabelText="Contraseña:" TitleText="Inicio de sesión"
  5.         UserNameLabelText="Nombre de usuario:" LoginButtonImageUrl="~/Images/Botones/b_iniciarSesion.jpg" LoginButtonType="Image">
  6.     </asp:Login>
  7.    
  8. </asp:Content>

En el código de servidor de esa misma página, en el evento Load, coloca lo siguiente:

VB.NET:
  1. Login1.Focus()
  2. Dim FormaPpal As HtmlForm = Master.FindControl("form1")
  3. Dim Boton As ImageButton = Login1.FindControl("LoginImageButton")
  4. If Not FormaPpal Is Nothing And Not Boton Is Nothing Then
  5.     FormaPpal.DefaultButton = Boton.UniqueID
  6. End If

Estamos estableciendo la propiedad DefaultButton del control Form en el botón del Login. Por cierto, esta propiedad también existe en el control Panel, podría ser útil en algún otro caso. Esta propiedad está diciendo que cuando se oprima la tecla Enter, se debe realizar la misma acción que cuando se hace clic en el botón indicado.

form1 es el nombre del formulario que aparece en el MasterPage

LoginImageButton no aparece en ninguna parte, pero es el nombre que se le da por default al botón de submit, ya que yo utilicé un botón de imagen.

En caso de que uses un botón regular utiliza Button en la declaración y LoginButton en el FindControl (línea 3).

Ahora bien, todo arreglado con el Login, pero cuando intento hacer una búsqueda tecleando una palabra en el campo de búsqueda (que vive en el MasterPage) y oprimo la tecla Enter, entonces se intenta enviar el formulario de inicio de sesión.

Además, en todas las otras páginas basadas en el MasterPage (y que no contienen el Login) cuando tecleo una palabra de búsqueda y oprimo Enter solamente se hace un postback, pero no se efectúa la búsqueda.

Para solucionar el problema, basta abrir el MasterPage y establecer dicha propiedad:

ASP:
  1. <form id="form1" runat="server" DefaultButton="BotonIr">

BotonIr es mi botón que al ser oprimido envía a la página que realiza la búsqueda.

¡Listo! :D

Jun 26

El GridView provee una propiedad EmptyDataText en la que nosotros establecemos un texto que se desplegará si no se encuentran registros.

En un DataList no existe esta propiedad. Para mostrar el mensaje nos tenemos que valer de un Label:

ASP:
  1. <asp:Label ID="Mensaje" runat="server" Text="No se encontraron registros."></asp:Label>

Después tenemos que utilizar el evento DataBinding para mostrar el mensaje y el evento ItemDataBound para ocultarlo.

El evento DataBinding ocurre primero que ItemDataBound, es por eso que al principio lo mostramos, y luego en el siguiente evento probamos si existen registros, y si no existen, lo mostramos.

La lógica queda así:

VB.NET:
  1. Protected Sub DataList2_DataBinding(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataList2.DataBinding
  2.  
  3.     Mensaje.Visible = True
  4.  
  5. End Sub
  6.  
  7.  
  8. Protected Sub DataList2_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles DataList2.ItemDataBound
  9.  
  10.     If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
  11.         Mensaje.Visible = False
  12.     End If
  13.    
  14. End Sub

Jun 25

Para hacer que se abra un Popup (o ventana emergente) desde una página web, colocamos este código de JavaScript dentro del tag body:

HTML:
  1. <body onLoad="window.open('popup.html','','width=500,height=500')">

Ahora bien, se abre el Popup con la página popup.html. Una vez hecho esto, quiero que al oprimir una liga (ya sea imagen o texto) se cierre el popup y la ventana principal cambie a otra dirección.

Para hacerlo, debemos colocar esta liga en la página popup.html:

HTML:
  1. <a href="javascript: window.opener.location.href = 'http://www.yahoo.com'; window.close();">Ciérrame y cambia de página la ventana principal</a>

Como puedes ver hay dos instrucciones de JavaScript, la primera modifica el URL de la ventana principal y la segunda cierra el popup.

opener hace referencia a la ventana desde la cual se mandó llamar el popup.

Para hacerlo en Flash

Si en tu Popup tienes una animación en Flash y quieres hacer lo mismo, es sencillo, coloca este código en un botón:

Actionscript:
  1. on(release) {
  2.    getURL("javascript: window.opener.location.href = 'http://www.yahoo.com'; window.close();");
  3. }

Jun 25

Estoy trabajando con un DataList y dentro de su ItemTemplate tengo lo siguiente:

ASP:
  1. <asp:Image ID="Image1" runat="server" ImageUrl='<%# Funciones.DameURLImagen(Eval("Imagen")) %>' />

La función DameURLImagen debe revisar el parámetro que se le manda. Si es de tipo DBNull quiere decir que ese campo es nulo en la base de datos, así que debe mostrar una imagen genérica. Si es un String, entonces debe verificar si está vacío o no. Si lo está, se debe mostrar nuevamente la imagen genérica. Si no lo está se debe mostrar la imagen extraída de la base de datos.

Este chequeo de tipo se hace mediante TypeOf.

Aquí está nuestra función DameURLImagen:

VB.NET:
  1. Shared Function DameURLImagen(ByVal Imagen As Object) As String
  2.     If IsDBNull(Imagen) Then
  3.         DameURLImagen = "~/Images/NoHayImagen.jpg"
  4.     Else
  5.         If TypeOf (Imagen) Is String Then
  6.             If Imagen = "" Then
  7.                 DameURLImagen = "~/Images/NoHayImagen.jpg"
  8.             Else
  9.                 DameURLImagen = "~/Images/" & Imagen
  10.             End If
  11.         Else
  12.             DameURLImagen = "~/Images/NoHayImagen.jpg"
  13.         End If
  14.     End If
  15. End Function

Jun 25

En algunos casos uno tiene un formulario mediante el cual se dan de alta registros y se desea que la alta sea continua. Es decir, que al dar de alta un registro y oprimir un botón para guardar, la página limpie todos los campos y quede lista para volver a empezar.

Normalmente uno pensaría en restablecer todos los campos mediante código de servidor, justo después de hacer la inserción en la base de datos, algo como esto:

VB.NET:
  1. TextBox.Text = ""
  2. DropDown1.SelectedValue = "sinseleccion"
  3. CheckBox1.Checked = False

En ocasiones no tenemos tres campos, sino 20, 30, o 40.

Para no tener que hacer el recorrido manual por cada uno de los campos, simplemente hay que hacer un redireccionamiento a la misma página. Suponiendo que nuestra página se llama Alta.aspx, haríamos esto:

VB.NET:
  1. Response.Redirect("Alta.aspx")

Y listo, el Response.Redirect manda nuevamente a la misma página, sin hacer un postback.

Jun 24

Para obtener el ancho, el alto, y el tamaño en KBytes de una imagen, utiliza el siguiente código:

VB.NET:
  1. Dim Im As New System.Drawing.Bitmap("c:\Imagen.jpg")
  2. Dim FIm As New FileInfo("c:\Imagen.jpg")
  3. Dim TamanoBytes, TamanoKBytes As Long
  4. TamanoKBytes = FIm.Length / 1024
  5. TamanoBytes = FIm.Length 'Por si lo quieres en Bytes
  6. 'InfoImagen es un Label
  7. InfoImagen.Text = "Ancho: " & Im.Width & " pixeles; Alto: " & Im.Height & " pixeles; Tamaño: " & TamanoKBytes & " KB;"
  8. 'Siempre recuerda cerrar el Bitmap
  9. Im.Dispose()

Si no cierras el Bitmap utilizando su método Dispose, aparecerá un error que dice que la imagen está siendo utilizada por otro proceso cuando la quieras borrar o modificar su nombre.

Jun 20

El RollOver es un efecto mediante el cual se muestra una imagen cuando el ratón se encuentra lejos, y otra imagen cuando el ratón se pasa sobre la imagen.

No existe un control de servidor en ASP.NET para crear un efecto RollOver. Para hacerlo tendríamos que añadir un control de tipo LinkButton y luego añadir algo de JavaScript mediante código de servidor. Suena muy complicado si tenemos, por ejemplo, una barra de navegación con varias opciones de menú.

Buscando en Google encontré este artículo de Scott Mitchell. Basándose en el concepto de herencia, se crea un nuevo control llamado RollOver que hace justamente lo que queremos.

No voy a entrar en los detalles de programación, porque los puedes leer en la liga antes mencionada, pero sí te voy a explicar cómo hacerlo funcionar en 1 minuto.

En la carpeta raíz de tu aplicación, crea un fólder llamado bin (si es que no lo tienes ya), y coloca ahí el archivo .dll que descargaste.

Listo, esta es toda la configuración que tienes que hacer, ahora, para utilizarlo tienes que registrarlo en cada una de las páginas en las que lo vayas a usar. Para hacerlo, pega esta línea al principio del código de tu página:

ASP:
  1. <%@ Register TagPrefix="skm" Namespace="RolloverButton" Assembly="RolloverButton" %>

Y para usarlo, pega este código en el lugar donde quieras que aparezca el RollOver:

ASP:
  1. <skm:RollOver
  2.         runat="server"
  3.         id="RollOver1"
  4.         ImageUrl="Images/Icono_Home.gif"
  5.         RollOverImageUrl="Images/Icono_HomeOn.gif"
  6.         PostBackUrl="Default.aspx"
  7.         Height="100px"
  8.         ToolTip="Ir a Inicio"
  9.         Width="100px" />

  • ImageUrl: Es la imagen que aparecerá cuando el ratón esté lejos.
  • RollOverImageUrl: Es la imagen que aparecerá cuando el ratón pase sobre el control.
  • PostBackUrl: Es la liga a la cual se llevará al hacer clic sobre la imagen.

Como otro ejemplo, te pongo el código de una página que se crea a partir de un MasterPage:

ASP:
  1. <%@ Page Language="VB" MasterPageFile="~/Ppal.master"
  2.         AutoEventWireup="false" CodeFile="Tira.aspx.vb"
  3.         Inherits="Tira" title="Untitled Page" %>
  4.        
  5. <%@ Register TagPrefix="skm" Namespace="RolloverButton" Assembly="RolloverButton" %>
  6.  
  7. <asp:Content ID="Content1" ContentPlaceHolderID="Cuerpo" Runat="Server">
  8.  
  9.     <skm:RollOver
  10.             runat="server"
  11.             id="RollOver1"
  12.             ImageUrl="Images/Icono_Home.gif"
  13.             RollOverImageUrl="Images/Icono_HomeOn.gif"
  14.             PostBackUrl="Default.aspx"
  15.             Height="100px"
  16.             ToolTip="Ir a Inicio"
  17.             Width="100px" />
  18.     <br />
  19.  
  20. </asp:Content>

Nota: Este control no soporta el uso de la tilde (~) para designar al directorio raíz.

Jun 20

Al crear un TableAdapter en una aplicación de ASP.NET 2 usando Visual Web Developer 2005 Express, se establecen algunos límites que no son obvios a primera vista.

En un proyecto en el que trabajo tengo una base de datos en MySQL con un campo llamado Cuerpo que es de tipo longtext y está diseñado para que pueda almacenar varios párrafos de HTML.

Al crear el TableAdapter y el Business Logic uno nunca establece los tamaños de los campos, ya que la herramienta lo hace por uno mismo.

En mi caso, al insertar un registro mediante mi aplicación, el campo Cuerpo se truncaba, almacenando únicamente alrededor de 1000 o 1024 caracteres.

Mi primera idea fue ir a revisar mi tabla de MySQL, pero el límite no estaba ahí. En seguida fui a ver las propiedades de la tabla en el TableAdapter de mi aplicación:

Propiedades

Como puedes ver, el MaxLength del campo en cuestión estaba establecido en 60,000, así que tampoco estaba ahí el problema. Después de un rato de darle vueltas al asunto, se me ocurrió ver las propiedades de la sentencia que hacía el insert en la base de datos, la cual en mi ejemplo se llama InsertaEnvio. Solamente hay que seleccionarla y oprimir el pequeño botón con tres puntos:

TableAdapter

Se mostrará la ventana de propiedades de la sentencia SQL. Seleccioné el campo problemático, y noté que en la propiedad Size tenía un valor de 1024:

Tamano del campo

Listo, ahí estaba el error, solamente lo modifiqué a un valor lo suficientemente grande:

Tamano modificado

Salve el archivo xsd, probé nuevamente, y el problema desapareció.

Jun 19

Es posible modificar el tag Title y añadir Metatags y otros elemenos al Head de nuestra página mediante el código de servidor.

Esto puede ser muy útil si estamos utilizando MasterPages. Añadimos el código una vez a nuestro MasterPage, y éste se encarga de colocar estos valores a lo largo de toda nuestra aplicación.

El código siguiente establece el título de la aplicación, crea un Metatag para Keywords, otro para Description y finalmente agrega la referencia a un archivo .js de JavaScript. Lo interesante de esto último es que mediante la función Page.ResolveUrl se genera dinámicamente la ruta del .js partiendo de la ruta raíz de la aplicación. Si existen páginas creadas a partir del MasterPage en diferentes niveles de carpeta (o si movemos la página a alguna subcarpeta) la ruta al script siempre se generará correctamente.

Este es el código:

VB.NET:
  1. Page.Title = "Trebol, todo tipo de articulos de papeleria"
  2.  
  3. Dim PalabrasClave As New HtmlMeta()
  4. PalabrasClave.Name = "Keywords"
  5. PalabrasClave.Content = "colores, lapices, plumas"
  6.  
  7. Dim Descripcion As New HtmlMeta()
  8. Descripcion.Name = "Description"
  9. Descripcion.Content = "Articulos de papeleria"
  10.  
  11. Dim ScriptCambiadorEstilos As New HtmlGenericControl("script")
  12. ScriptCambiadorEstilos.Attributes.Add("type", "text/javascript")
  13. 'Recuerda que la tilde (~) indica la raiz de tu aplicacion
  14. ScriptCambiadorEstilos.Attributes.Add("src", Page.ResolveUrl("~/scripts/styleswitch.js"))
  15.  
  16. Dim Cabeza As HtmlHead = CType(Page.Header, HtmlHead)
  17. Cabeza.Controls.Add(PalabrasClave)
  18. Cabeza.Controls.Add(Descripcion)
  19. Cabeza.Controls.Add(ScriptCambiadorEstilos)

Jun 18

Al tratar de compilar (Build) una aplicación de ASP.NET 2 aparece el siguiente error:

Error 1 Es incorrecto utilizar una sección registrada como allowDefinition='MachineToApplication' mas allá del nivel de aplicación. Este error puede tener como origen un directorio virtual que no esté configurado como aplicación en IIS. W:\AmexCuestionarioClubVacaciones\server\Web.config 87

En inglés:

Parser Error Message: It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.

En mi caso esto se debía a que tenía un archivo web.config dentro de una subcarpeta de la aplicación raíz. Estaba guardando ese archivo como backup, y era lo que impedía que el proyecto se compilara, marcando el error anterior.

Tan pronto como lo renombré a web.config.txt desapareció el error.

« Previous Entries