miércoles 8 de julio de 2009

ASP.NET – Deshabilitar autocompletado de textbox

input_AutoComplete Se habrán dado cuenta que la mayoría de exploradores nos dan la facilidad de guardar los textos que escribimos en las páginas web, como la imagen mostrada.

Pero, pero, pero… no siempre queremos que esta funcionalidad esté activada… porque imagínense que en una página ingresas tu número de tarjeta de ahorros y luego otra persona accede desde tu PC al mismo formulario de la página, KATABOOM!!! verá tu número de tarjeta… y eso no es lo que queremos verdad?

Entonces, vamos a mostrar cómo se debe hacer para que a veces no se active el autocompletado de los controles.

1.- Si estás usando un control html input, lo único que debes hacer es añadir el texto autocomplete=”off”

<input id="Text1" type="text" autocomplete="off" />

2.- Si estás usando un control ASP.NET textbox, podemos hacerlo de dos maneras:

  • usamos el atributo AutoCompleteType="Disabled", vea:

<asp:TextBox ID="txt1" AutoCompleteType="Disabled" runat="server"></asp:TextBox>

  • o via programación:

txt1.Attributes.Add("autocomplete", "off");

Ambas maneras nos brindan el mismo resultado… osea, el control asp:textbox finalmente renderizará en lo sgte:

<input id="txt1" type="text" autocomplete="off" />

Así de simple ;)

viernes 3 de julio de 2009

ASP.NET – primer caracter y todo el texto a mayusculas convertir

aspnet Hay varios casos que podemos analizar:

Caso 1: Convertir todo el texto a mayúsculas usando un estilo css:

En el head de la página aspx creamos el estilo:

<style type="text/css">
.ToUpper
{
text-transform: uppercase;
}
</style>

Luego, al control textbox le añadimos el atributo cssClass=”ToUpper”

<asp:TextBox ID="TextBox1" CssClass="ToUpper" runat="server"></asp:TextBox>

<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Guardar" />

Esta es la forma más simple de realizar esta conversión… cualquier texto que el usuario tipee, será disfrazado en mayúsculas, digo disfrazado porque no es una verdadera conversión, sólo nos lo muestra en mayúsculas, pero el texto sigue en minúsculas…

y digamos que deseas guardar la data del textbox en el servidor EN MAYÚSCULAS, pues simplemente usamos el método ToUpper del textbox y problema solucionado:

protected void Button1_Click(object sender, EventArgs e)
{
string strText = TextBox1.Text.ToUpper();
}

Si quisieras más bien mostrar en minúsculas, harías esto en el css:

text-transform: lowercase;

y esto en el click del botón:

TextBox1.Text.ToLower();

Caso 2: Convertir todo el texto a mayúsculas obligándole al usuario a que escriba todo en mayúsculas ;)

Para esto, añadimos un control requiredfieldvalidator y un control regular expressionvalidator:

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ErrorMessage="*" ControlToValidate="TextBox1" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server"
ErrorMessage="Todos los caracteres deben estar en mayúscula" ControlToValidate="TextBox1" Display="Dynamic"
ValidationExpression="^[A-Z]*$"></asp:RegularExpressionValidator>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Guardar" />

Esta situación es útil por ejemplo cuando deseamos que el usuario sea consciente de lo que ingresa.

Caso 3: Convertir todo el texto a mayúsculas , haciendo uso de javascript,

En el head de la página aspx insertamos la función javascript:

<script type="text/javascript">
function changeToUpperCase(controlName)
{
document.getElementById(controlName).value = document.getElementById(controlName).value.toUpperCase();
}
</script>

Luego, del lado del code-beside:

protected void Page_Load(object sender, EventArgs e)
{
TextBox1.Attributes.Add("onkeyup","changeToUpperCase(this.id)");
TextBox1.Attributes.Add("onchange", "changeToUpperCase(this.id)");
}

protected void Button1_Click(object sender, EventArgs e)
{
string strText = TextBox1.Text;
}

Caso 4: Convertir sólo el primer caracter de cada palabra a mayúsculas , para este caso hacemos uso de alguna cultura que ya mantenga estas especificaciones… como por ejemplo la cultura norteamericana ( en-US ) quien considera que en los títulos el primer caracter deba ir en mayúsculas, veamos el ejemplo:

En este caso, para el lado aspx no hacemos nada más que tener el textbox y el boton:

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Guardar" />

y en el clik del botón:

protected void Button1_Click(object sender, EventArgs e)
{
System.Globalization.TextInfo TI = new System.Globalization.CultureInfo("en-US", false).TextInfo;

string strText = TI.ToTitleCase(TextBox1.Text);
}

Eso es todo por ahora ;)

jueves 25 de junio de 2009

ASP.NET – Sobreescribir contenido de master pages

master Primero, analicemos algunas situaciones que comúnmente se dan cuando desarrollamos apliaciones web:

+A menudo, las aplicaciones son usadas por personas que tienen roles… osea, algunos tienen más privilegios que otros… esto significa que no todos pueden borrar, editar o ver toda la  información.

+Dependiendo del rol o derechos que tenga cierto usuario, es probable que el menú que pueda usar no es el mismo que usarán los demás… a veces usarán un menú de usuario, otras veces el menú de Administración… y otras veces no podrán acceder a ciertas zonas.

+La estructura de las páginas web casi siempre será la misma: una cabecera, un pie de página, un menú a la derecha o un menú inmediatamente después de la cabecera… el contenido va a la derecha o al centro, o el menú a la derecha y el contenido a la derecha, etc… casi siempre es así.

Entonces, es cuando vemos la tremenda utilidad que tiene una master page, pues nos prmite precisamente crear una sola estructura y añadir/quitar contenido, según corresponda… y si hay que modificar algo, se modifica la master page y fuahhh!!!, todo se actualiza.

Luego que ya hemos acordado algunas verdades casi indiscutibles, y como hemos dicho que la mayoría de veces el contenido es el mismo, pero que en algunas páginas no queremos cierto contenido… vamos a ver cómo quitamos ese contenido.

Lo que vamos a hacer es sobreescribir el contenido de las mater pages… para en su lugar poner nuevo contenido, y dice así:

1.- Abran Visual Studio y elijan Crear… Proyecto, elijan Aplicación web ASP.NET

2.- Añadan una master page a su proyecto, llámenla site1.master y agreguen la sgte estructura dentro del elemento form:

     <div style="width:100%;height: 100px;float:left">
        <asp:ContentPlaceHolder ID="cabecera_va_aqui"  runat="server">
            <h1>Cabecera va aquí</h1>
        </asp:ContentPlaceHolder>
    </div>


    <div style="width: 30%;height: 500px;float:left">
        <asp:ContentPlaceHolder ID="menu_izquierda_va_aqui" runat="server">
            <h1>un menú por defecto va aquí</h1>
        </asp:ContentPlaceHolder> 
    </div>


    <div style="width: 65%;height: 500px; float:right">
       <asp:ContentPlaceHolder ID="cuerpo_va_aqui" runat="server">


        </asp:ContentPlaceHolder>        
    </div>


    <div style="width:100%;height: 50px;float:left">
       <asp:ContentPlaceHolder ID="pie_va_aqui" runat="server">
            <h1>Pie de pagina va aquí</h1>
        </asp:ContentPlaceHolder>             
    </div>

Observen que a la master page le he creado secciones para cabecera, menu izquierdo, cuerpo y pie de pagina… y además de esto, ya le he agregado contenido a la cabecera, al menu izquierdo y al pie de página.

3.- Agreguen un nuevo elemento a su proyecto, agreguen un Formulario de contenido web, llámenlo WebForm1.aspx… les ofrecerá la opción de elegir una master page, elijan site1.master.

Ahora analicemos el código aspx de la página generada:

<asp:Content ID="Content1" ContentPlaceHolderID="cabecera_va_aqui" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="menu_izquierda_va_aqui" runat="server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="cuerpo_va_aqui" runat="server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="pie_va_aqui" runat="server">
</asp:Content>

Se han creado las zonas para agregar contenido en la página… pero antes que nada, presionen F5 para ver la página WebForm1.aspx en acción… qué ven en la página? nada verdad? eso es porque no hemos agregado nada en las zonas Content de la página…

Professsor, professor, pero yo quiero ver la cabecera que puse en mi master page, y mi menú, y mi pie de página…

Ahhhhh, para eso debes borrar los Content que ya no quieres sobreescribir, deberías borrar lo tachado:

<asp:Content ID="Content1" ContentPlaceHolderID="cabecera_va_aqui" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="menu_izquierda_va_aqui" runat="server">
</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="cuerpo_va_aqui" runat="server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="pie_va_aqui" runat="server">
</asp:Content>

Y ahora ejecuta nuevamente la página y mira el cambio.

Excelente no es cierto?

Ahora, si quisieras sobreescribir el menú de la izquierda por otro menú –digamos de administrador- , sólo tienes que insertar tu nuevo menú en el Content respectivo, dentro de la página de contenido:

<asp:Content ID="Content2" ContentPlaceHolderID="menu_izquierda_va_aqui" runat="server">

El nuevo menú iría aquí……………………………
</asp:Content>

Esta técnica de poner algún contenido dentro de un contentplaceholder en la master page se usa sobre todo cuando hay algún contenido que se va a mantener en la mayoría de páginas, pero que en algunas irá otro contenido… y como has visto, es posible sobreescribirlas.

Y si hay algún contenido que nunca vas a sobreescribir, pues no es necesario que en la master page vaya dentro de un contentplaceholder.

Y eso es todo ;)

lunes 22 de junio de 2009

.NET – Agregarle descripcion a un Enum

enum_desc Ya hemos revisado en el post anterior, cómo podemos iterar por los elementos de una enumeración.

Ahora, vamos a ver cómo se hace para añadirle una descripción a una enumeración... y luego, cómo recuperamos esa enumeración.

Para nuestro propósito, vamos a usar Reflection.

1.- Importamos
Imports System.ComponentModel
Imports System.Reflection

2.- Para añadirle una description a nuestro enum, hacemos esto:
Enum Roles
<Description("Administrador general del sistema")> Administrador = 1
<Description("Usuario de la aplicación, con derechos limitados")> Usuario = 2
<Description("Auditor del sistema")> Auditor = 3
<Description("Persona que no es usuario de la aplicación")> Invitado = 4
End Enum
3.- De esta forma recuperamos las descripciones de la enumeración:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sb As New StringBuilder
Dim enumValores As FieldInfo() = GetType(Roles).GetFields()
For Each info As Reflection.FieldInfo In enumValores
If Not info.IsSpecialName Then

Dim obj As Object = info.GetCustomAttributes(GetType(DescriptionAttribute), False)
Dim desc As DescriptionAttribute = DirectCast(obj(0), DescriptionAttribute)

sb.Append(desc.Description & "<br />")

End If
Next info

Response.Write(sb.ToString)
End Sub


Y es sería todo. ;)

jueves 18 de junio de 2009

.NET - Recorrer los elementos de un Enum

enum Tenemos un Enum:

Enum Roles
Administrador = 1
Usuario = 2
Auditor = 3
Invitado = 4

End Enum

y queremos recorrer o iterar por sus elementos… cómo lo hacemos?

en realidad es nada dificil, veamos 2 formas:

1.- Obtenemos los valores del Enum en un array, luego de eso iteramos por el array y ya tenemos todos los elementos:

Dim values As Array
values = System.Enum.GetValues(GetType(Roles))
Dim valuesString As New StringBuilder
For Each val As String In values
    valuesString.AppendFormat("{0},", val)
Next
Dim TotalValues As String = valuesString.ToString

Dim names As Array
names = System.Enum.GetNames(GetType(Roles))
Dim namesString As New StringBuilder
For Each name As String In names
    namesString.AppendFormat("{0},", name)
Next
Dim TotalNames As String = namesString.ToString

Para este caso, he tenido que crear dos arrays, uno para obtener los valores… y otro para sus nombres.

También pueden iterar de una sola vez, y obtener ambos datos… pero lo haremos usando Reflection… como se explica en la siguiente forma:

2.- Esta vez, lo que vamos a usar son las funcionalides del espacio de nombres System.Reflection… y de ella la clase FielInfo, que lo que hace es particionar alguna información y exponer dicha metadata.

Si desean saber más sobre FieldInfo, hagan click aquí

Para recorrer por cada uno de los elementos y recuperar su valor y nombre, usamos la siguiente rutina:

Dim enumValores As Reflection.FieldInfo() = GetType(Roles).GetFields()

For Each info As Reflection.FieldInfo In enumValores

If Not info.IsSpecialName Then
Dim val As Integer = info.GetValue(0)
Dim nom As String = info.Name
End If

Next info

Eso sería todo ;)

miércoles 3 de junio de 2009

ASP.NET - Enviar correos asíncronos

async_email La forma normal de enviar correos es síncrona, osea se intenta enviar el email y esperamos la respuesta de envío exitoso o de error.
Si enviamos un correo que probablemente tome su tiempo en llegar a su destino, ocurrirá que tendremos que esperar a que el correo se termine de enviar,
lo cual en ASP.NET se refleja en una pantalla congelada que de a pocos se va cargando, y como deducirías, afecta a toda la aplicación... ya que ese tiempo que se tarda en enviar el correo es tiempo perdido para el usuario.

ASP.NET permite enviar realizar tareas de manera asíncrona, esto quiere decir que podemos enviar un correo y no tenemos que esperar a ver si se envió correctamente, sino que podemos continuar con nuestra navegación por el resto de páginas.

Veamos cómo sería esto:

El primer paso es incluir el atributo Async al elemento @Page:

<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebForm1.aspx.cs"
Inherits="SamplesCS.WebForm1"
Async="true" %>

En el code-beside, se requiere incluir los sgtes espacios de nombres:

using System.Net.Mail;
using System.Net;
using System.ComponentModel;

Luego este método hace el trabajo sucio:

public void SendEmail(string strFrom, string strTo, string strSubject, string strBodyText)
{
MailMessage Mail = new MailMessage();
Mail.From = new MailAddress(strFrom);
Mail.To.Add(strTo);
Mail.Subject = strSubject;
Mail.Body = strBodyText;
SmtpClient SMTPClient = new SmtpClient();
NetworkCredential basicAuthenticationInfo = new NetworkCredential("algun_correo1", "algun_password1") ;
SMTPClient.Host = "algun_email_host";
SMTPClient.UseDefaultCredentials = true;
SMTPClient.Credentials = basicAuthenticationInfo;

SMTPClient.SendCompleted += new SendCompletedEventHandler(CheckIfError);
SMTPClient.SendAsync(Mail, Mail);


}

Chequeen las líneas con negrita, esas son las que hacen el trabajo ásíncrono, observen también que recibe un parámetro llamado CheckIfError, ese es el delegado para el evento SendCompleted, y se usa cuando se termina la operación... para determinar si el email se envió correctamente o hubo algún error.

private static void CheckIfError(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null || e.Cancelled)
{
//podrías escribir el error a un archivo de texto
}
else
{
//podrías grabar el éxitoso envío a un archivo de texto.
}
}

Si revisan el método… en la parte comentada se sugiere guardar en un archivo de texto si la operación fue exitosa o no… de esta manera cuando el usuario desee determinar si hubo error, simplemente accede al archivo de texto. De esta manera no tenemos que estar creando código que trate con los resultados de la operación asíncrona, dado que no sabemos cuánto puede tardar, ni si ya se realizó.

;)

viernes 29 de mayo de 2009

Regresar a la ultima posicion del cursor

menu Recuerdan lo práctico que resultaba hacer click derecho sobre el nombre de un método y elegir la opción Ir a Definición??? y fuah! aparecíamos en la primera línea del método?


Luego, para regresar a donde estábamos, simplemente hacíamos click derecho de nuevo y elegíamos última posición... y fuah! regresábamos a donde estábamos inicialmente.

Aparentemente, esta funcionalidad se perdió en Visual Studio .NET, lo cual no es así... aún existe, está escondidito... si quieres regresar a la última posición, debes presionar CTRL + -

;)

miércoles 27 de mayo de 2009

CSS - Quitar el espacio entre celdas

Se dice constantemente que el uso de tablas no es recomendado, pero también hay que reconocer que a veces son necesarias,
por ejemplo cuando quiero crear un formulario con abundantes controles... es la mejor forma de mostrarlo de manera ordenada y alineada, sin descuidar la presentación, y con un poquito de estilos css, se ven muy bien.

Vamos a ver un ejemplo chiquitito:
Si mostramos una tabla tal como es (sin estilos) no se ve muy agradable, así que vamos a pintarle los bordes de
rojo por ejemplo. Para ellos usamos el sgte css:
table
{
border: 1px solid red;
}
td
{
background-color: Lime;
border: 1px solid red;
}

Observen el espacio entre celdas, ami no me gusta... para quitarlo, simplemente le añadimos al elemento table lo sgte:
border-collapse: collapse;

con lo que el estilo quedaría así:
table
{
border: 1px solid red;
border-collapse: collapse;
}
td
{
background-color: Lime;
border: 1px solid red;
}

Y quedaría así:

;)

viernes 22 de mayo de 2009

Instalar todas las versiones de Internet Explorer a la vez

iecollection Hemos notado como IE ha ido evolucionando… y con el paso de los años se fue pegando más a los estándares.

Y según esto, tenemos que entender que no todos las versiones de IE muestran la página web de la misma manera…

pregunta:usualmente, cómo haces para testear tu página ante diferentes versiones de IE?

Simple, usas tantas máquinas como IE desees testear… pero eso no es óptimo… lo óptimo sería tener la capacidad de abrir varias versiones del IE en una misma máquina… pero ya sabemos que el IE sólo mantiene una versión por máquina.

Por eso, les presento al espectacular programa IECOLLECTION… que instala todas las versiones de IE de un sólo golpe: desde la versión 1.xx hasta la 8.xx.

Les dejo el link para que lo prueben: IECOLLECTION

;)

viernes 8 de mayo de 2009

ASP.NET – Enviar correos con archivos adjuntos

email Para enviar correos con archivos adjuntos, tenemos dos maneras,

1.- adjuntamos el archivo indicándole la ruta física donde está ubicado (en el servidor, claro):

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Dim mail As New MailMessage

    mail.From = New MailAddress("algun_correo1")
    mail.To.Add("algun_correo2")

    mail.Subject = "Email de prueba con archivo adjunto"
    mail.Body = "chequea el archivo adjunto que viene en este email"

    Dim FilePath As String = Server.MapPath("~/files/simple_file.txt")
    'el archivo se adjunta indicándole la ruta
    mail.Attachments.Add(New Attachment(FilePath))

    Dim mailClient As New SmtpClient()

    Dim basicAuthenticationInfo As New NetworkCredential("algun_correo1", "algun_password1")

    mailClient.Host = "algun_email_host"

    mailClient.UseDefaultCredentials = True
    mailClient.Credentials = basicAuthenticationInfo
    mailClient.Send(mail)

End Sub

Este caso es útil cuando ya tenemos guardado el archivo en el servidor.

2.- Obtenemos el archivo mediante el control FileUpload, osea el archivo está en la máquina del cliente… sin necesidad de previamente guardarlo en el servidor:

Código ASPX:

<form id="form1" runat="server">
    <asp:FileUpload ID="FileUpload1" runat="server" />
    <br /><br />
    <asp:Button ID="Button1" runat="server" Text="Enviar correo con archivo adjunto" />
</form>

Código VB.NET:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

End Sub

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
    Dim mail As New MailMessage

    mail.From = New MailAddress("algun_correo1")
    mail.To.Add("algun_correo2")

    mail.Subject = "Email de prueba con archivo adjunto"
    mail.Body = "chequea el archivo adjunto que viene en este email"

    If FileUpload1.HasFile Then

        Dim MyFile As String = System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName)
        Dim attachmentFile As New Attachment(FileUpload1.PostedFile.InputStream, MyFile)
        mail.Attachments.Add(attachmentFile)

    End If

    Dim mailClient As New SmtpClient()

    Dim basicAuthenticationInfo As New NetworkCredential("algun_correo1", "algun_password1")

    mailClient.Host = "algun_email_host"

    mailClient.UseDefaultCredentials = True
    mailClient.Credentials = basicAuthenticationInfo
    mailClient.Send(mail)

End Sub

Para ambos casos debemos importar:

Imports System.Net
Imports System.Net.Mail

Cualquier duda, comentan?

miércoles 29 de abril de 2009

Comparar no es lo mismo que diferenciar ( sobre las fechas y .NET)

oclock Recordé lo dificil que me parecía encontrar la diferencia entre dos fechas. Ahora veo que este mismo problema lo tienen muchos developers. Así que es el momento de inmortalizar este tema con un post.

El título de este post dice que comparar no es lo mismo que diferenciar… y es cierto.

.net tiene el método Compare, que nos permite comparar fechas… osea, podemos usar este método cuando queremos saber si dos fechas son iguales, o si una es mayor que la otra… nada más. Veamos:

Dim date1 As Date = #4/27/2009 1:25:00 PM#
Dim date2 As Date = #4/28/2009 12:25:00 PM#
Dim result As Integer = DateTime.Compare(date1, date2)

Dim Respuesta As String

If result < 0 Then
    Respuesta = "date1 es menor"
ElseIf result = 0 Then
    Respuesta = "ambas fechas son iguales"
Else
    Respuesta = "date1 es mayor"
End If

Sigamos, si queremos saber en cuánto exactamente una fecha es mayor que otra.. entonces usamos el método DateDiff, este método nos permite hallarla diferencia entre dos fechas, pero especificándole si queremos obtener la diferencia en días, en horas, en minutos, en segundos, etc…

Dim Respuesta As String
Dim date1 As Date = #4/27/2009 1:25:00 PM#
Dim date2 As Date = #4/28/2009 12:25:00 PM#

Respuesta = "La diferencia en días es: " & DateDiff(DateInterval.Day, date1, date2)
Respuesta = "La diferencia en horas es: " & DateDiff(DateInterval.Hour, date1, date2)
Respuesta = "La diferencia en minutos es: " & DateDiff(DateInterval.Minute, date1, date2)
Respuesta = "La diferencia en segundos es: " & DateDiff(DateInterval.Second, date1, date2)

En realidad, este método es mucho más versátil, pero para nuestro tema es suficiente. Uds pueden indagar más sobre este método en MSDN.

Pero hay una estructura que a mi parecer es la más idónea cuando se trata de comparar fechas, se llama TimeSpan, esta estructura trae lo que tiene el método DateDiff y de una sola pasada… osea, si quieres saber la diferencia en días, horas, minutos, segundos, milisegundos, etc… TimeSpan es la voz:

Dim Respuesta As String
Dim date1 As Date = #4/27/2009 1:25:00 PM#
Dim date2 As Date = #4/28/2009 12:25:00 PM#

Dim tspan As TimeSpan
tspan = date2.Subtract(date1)
Respuesta = "La diferencia en días es: " & tspan.Days
Respuesta = "La diferencia en horas es: " & tspan.Hours
Respuesta = "La diferencia en minutos es: " & tspan.Minutes
Respuesta = "La diferencia en segundos es: " & tspan.Seconds

Resumen:

+ Para saber cuál de las fechas es mayor o menor o igual… sin importar por cuánto, suficiente con usar el método Compare.

+ Para saber la diferencia exacta entre dos fechas… ya sea en días, horas, minutos, segundos o milisegundos (uno de ellos) , suficiente con usar el método DateDiff.

+ Para saber la diferencia exacta entre dos fechas… tanto en días, horas, minutos, segundos y milisegundos (todos a la vez) usa la estructura TimeSpan.

;)

jueves 16 de abril de 2009

Cargando propiedades de user control creado dinamicamente

sample Me hicieron una pregunta: cómo se hace para cargar las propiedades de un control de usuario que ha sido creado dinámicamente.. en realidad la respuesta es bastante fácil, sólo que a veces no se nos ocurre cómo podría hacerse.

Vamos con un ejemplo:

Vamos a crear el control de usuario, lo llamaremos wucTest.ascx , el cual debe contener dos Labels….

<asp:Label ID="Label1" runat="server" BorderColor="red" BorderStyle="Solid"></asp:Label>
<br /><br />
<asp:Label ID="Label2" runat="server" BorderColor="green" BorderStyle="Solid"></asp:Label>

y le vamos a crear dos propiedades públicas… estas propiedades nos permitirán acceder a los Labels desde una página aspx…

Public Property ForLabel1() As String
    Get
        Return Label1.Text
    End Get
    Set(ByVal value As String)
        Label1.Text = value
    End Set
End Property

Public Property ForLabel2() As String
    Get
        Return Label2.Text
    End Get
    Set(ByVal value As String)
        Label2.Text = value
    End Set
End Property

Ahora, vamos a crear dinámicamente el control de usuario desde el Page_Load de la página aspx:

Dim Test As wucTest = CType(LoadControl("~/controls/wucTest.ascx"), wucTest)

Y le asignamos valores a los Labels, via sus propiedades:

Test.ForLabel1 = "texto 1"

Test.ForLabel2 = "texto 2"

Finalmente, cargamos el control de usuario en la página:

Page.Controls.Add(Test)

Es todo, como se habrán dado cuenta… de lo más natural.

sábado 4 de abril de 2009

Artes y malas artes - Nuestro segundo aniversario

Así es amigos... cómo pasa el tiempo:

Este blog acaba de cumplir su segundo añito...
Es un bebé que ya puede dar algunos pasitos!!!
Qué bien lo hemos pasado... vamos pa' lante nunca pa' trás... espero que nos sigamos viendo.

Como para que con el paso de los años recuerde en qué transcurría mi vida en el 2009... pongo la foto de mi hija Estefanía ("Tefita") de 4 años... quien hasta ahora es mi única y adorada hija.

ASP.NET – Validar controles agrupados con ValidationGroup

validationgroup En aquellos tiempos, una página web html podía (y puede) tener varios formularios para enviar información… me refiero a las páginas html (o php, o asp) … pero las páginas ASP.NET sólo pueden tener un formulario con runat=”server” dentro de su contenido.

Pero cómo hacemos si tenemos varias funcionalidades que necesitan enviar información por separado entonces?

Es simple… creas grupos de controles… por decir el grupo Login, que le permite al usuario loguearse e ingresar al sistema, este grupo tendría una caja de texto para ingresar el nombre de usuario y otra caja de texto para ingresar el password… podrías crear también otro grupo llamado GetPassword, que le permite al usuario solicitar su password si es que lo ha olvidado… y para hacer que la información se valide por separado…

Veamos el ejemplo:

<form id="form1" runat="server">

<fieldset>
<legend>Login</legend>
User:<asp:TextBox ID="txtUser" runat="server" ValidationGroup="Login"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="*" ValidationGroup="Login" ControlToValidate="txtUser" Display="Dynamic"></asp:RequiredFieldValidator>
<br />
Password:<asp:TextBox ID="txtPassword" TextMode="Password" ValidationGroup="Login" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ErrorMessage="*" ValidationGroup="Login" ControlToValidate="txtPassword" Display="Dynamic"></asp:RequiredFieldValidator>
<br />
<asp:Button ID="btnLogin" runat="server" ValidationGroup="Login" Text="Login" />
</fieldset>

<br />

<fieldset>
<legend>I&#39;ve forgotten my password</legend>
Email:<asp:TextBox ID="txtEmail" runat="server" ValidationGroup="GetPassword"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server"
ErrorMessage="*" ValidationGroup="GetPassword" ControlToValidate="txtEmail" Display="Dynamic"></asp:RequiredFieldValidator>
<br />
<asp:Button ID="btnGetPassword" runat="server" ValidationGroup="GetPassword"
Text="Get Password" />
</fieldset>

</form>

Lo que estoy haciendo es crear dos grupos de controles… diferenciados por el ValidationGroup atributo, cada grupo tiene su propio botón para submitir la información…

Pero esto, no es suficiente, como aprecian la validación se está haciendo con controles de validación, osea javascript… pero esta validación puede ser burlada muy fácilmente, cómo? simplemente desactivando el javascript del browser.

Nosotros vamos a añadir una verificación adicional, peor esta vez será del lado del servidor. Entonces, para validar cada grupo de controles por separado, dentro del botón correspondiente, simplemente ponemos:

Protected Sub btnLogin_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnLogin.Click
    Page.Validate("Login")

    If Page.IsValid Then
        'continue your logic
    Else
        'error
    End If
End Sub

Protected Sub btnGetPassword_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnGetPassword.Click
    Page.Validate("GetPassword")

    If Page.IsValid Then
        'continue your logic
    Else
        'error
    End If
End Sub

Fíjense que la línea que hace todo el trabajo de validar sólo un grupo de controles es Page.Validate(tu_grupo_de_validacion)

;)

jueves 26 de marzo de 2009

ASP.NET – Un validator para múltiples controles

customval Ya conocemos los controles de validación de ASP.NET, y también sabemos que trabajan sobre un control, no sobre múltiples controles... recordarás que tienen una propiedad llamada ControlToValidate.

Pero, hay ocasiones en las que tenemos dos controles.. y nos basta si se ingresa información a alguno de ellos... no necesariamente a ambos... pero por lo menos uno de ellos debe recibir un valor.

Con los controles de validación que tenemos no nos alcanza... por lo menos no en su forma común... pero se puede usar un sólo validator para verificar multiples controles?

claro que sí, ahora lo vamos a demostrar:

Creamos un pequeño formulario que nos permita ingresar el nombre y el alias de un usuario... el  control de validación deberá exigir que al menos se inngrese uno de los datos.

El control  que realizará esta validación será el CustomValidator, veamos cómo quedaría nuestro código aspx…

Este es el javascript que deben poner en el head de la página:

<script type="text/javascript">
function CustomValidator_ClientValidate(source, args)
{
    var nombre = document.getElementById("<%=txtNombre.ClientID %>");
    var alias = document.getElementById("<%=txtAlias.ClientID %>");
    if ((nombre.value + alias.value) == "")
        args.IsValid = false;
    else
        args.IsValid = true;
}
</script>

y el sgte es el código que pondremos dentro del tag FORM:

Nombre:<asp:TextBox ID="txtNombre" runat="server"></asp:TextBox>
<br />
Alias:<asp:TextBox ID="txtAlias" runat="server"></asp:TextBox>
<br />
<asp:Button ID="Button1" runat="server" Text="Enviar datos" />

<asp:CustomValidator ID="CustomValidator1" runat="server"
    ErrorMessage="Al menos ingrese un dato!"
    ValidateEmptyText="true"
    Display="Dynamic"
    ClientValidationFunction="CustomValidator_ClientValidate"
    OnServerValidate="CustomValidator_ServerValidate">
    </asp:CustomValidator>

Luego el código-beside:
    Protected Sub CustomValidator_ServerValidate( _
    ByVal source As Object, ByVal args As ServerValidateEventArgs)

        If txtNombre.Text & txtAlias.Text = "" Then
            args.IsValid = False
        Else
            args.IsValid = True
        End If

    End Sub

Aquí lo que hay que comentar es que estoy usando una función javascript CustomValidator_ClientValidate, desde la cual hago la verificación de ambos controles… y adicionalmente, tenemos el método CustomValidator_ServerValidate, el cual realiza la misma verificación, pero desde el servidor, ya que como sabemos, el javascript puede estar deshabilitado en el browser y la función no se ejecutaría… para eso prevenimos entonces usando el método CustomValidator_ServerValidate.

Ojo, que no estamos usando la propiedad ControlToValidate del CustomValidator en este caso.

Es todo. Cualquier duda, posteen su comentario.