Como Validar un ListBox (CustomValidator)

Siguiendo con las respuestas en los foros hoy voy a explicar como poder validar si tenemos seleccionado un elemento de una lista.


 http://forums.microsoft.com/MSDN-ES/ShowPost.aspx?PostID=3922327&SiteID=11


Para poder realizar esto de la forma más simple y que sea compatible con los otros validadores utilizaré un CustomValidator.


Crearé un formulario con una lista un customValidator y un botón para provocar la recarga de la página.


 


Para que la validación no influya en el rendimiento de la aplicación validaremos en el cliente y crearemos una función javascript para la validación.


<script type=“text/javascript”>
function ValidarListaSeleccionada(source, arguments)
{
var list = document.getElementById(source.controltovalidate);
if( list != null)
{
var listValue = list.value;
if(listValue ==””)
arguments.IsValid=false;
else
arguments.IsValid=true;
}
}
</script>

Este script es muy simple pero muy eficaz ;-).


Para crear una función que podamos utilizar con customValidator tiene que tener dos parámetros:




  • source: el control que lanza la validación (Nuestro customValidator).


  • arguments: donde informaremos si la validación ha tenido éxito o no. (arguments.IsValid=true)

La validación consiste en localizar el control que queremos validar gracias a la propiedad controltovalidate del customValidator y recuperar el valor seleccionado de la lista. Si el valor esta vacío quiere decir que el usuario no ha seleccionado nada.


 Una vez que tenemos la función creada configuraremos el validador para que la utilice.


<asp:CustomValidator ID=“CustomValidator1” runat=“server”
ControlToValidate=“ListBox1”
ErrorMessage=“Tienes que seleccionar un elemento de la lista.”
ClientValidationFunction=“ValidarListaSeleccionada”
ValidateEmptyText=“True”>
</asp:CustomValidator>

Importante:




  • ControlToValidate: 😉


  • ClientValidationFunction: La función JavaScript que hemos creado antes.


  • ValidateEmptyText: Para que valide el control aunque no se haya seleccionado.

 Y con esto ya hemos creado un validador personalizado para nuestra lista.


 


Happy Coding


Cross-posting http://lonetcamp.com/


 


 

El futuro de los Móviles está en el horno

Los móviles de última generación están empezando a sacar partido al impresionante filón que es el acelerómetro los desarrolladores están jugando con sus posibilidades y ya se pueden ver pruebas verdaderamente impresionantes.

Quien tenga ganas de testear se puede bajar el SDK  y hay varios ejemplos de códigos .




 Fuente http://www.xatakamovil.com/2008/09/15-touch-diamond-vr-hologram

Saludos.

Cross-Posting desde http://lonetcamp.com


 


 

[Asp.net] Editable Treeview II

Siguiendo con el anterior artículo de personalizar un TreeView I   para poder editar los nodos hoy veremos precisamente la parte donde habilitamos la edición de los nodos.


Crearemos una nueva clase que llamaremos TreeNodeEdit que heredara de TreeNode. Con esto ya tendremos la base para montar nuestro nodo editable.


[ToolboxData(“<{0}:TreeNodeEdit runat=server></{0}:TreeNodeEdit>”)]
public class TreeNodeEdit : TreeNode

Crearemos las propiedades públicas para poder configurar nuestro Nodo.



  • bool Editable –>Para hablilitar la edición del nodo.

  • string TextBoxValue –> Valor de la edición.

  • string OldValue –> Valor anterior a la edición.

  • string EditImageUrl –> Url del a imagen del botón editar.

  • string CancelImageUrl –> Url de la imagen del botón cancalar.

  • string SaveImageUrl –> Url de la imagen del botón guardar.

  • string EditTooltip –> Tooltip del botón editar.

  • string SaveTooltip –> Tooltip del botón guardar.

  • string CancelTooltip –> Tooltip del botón cancelar.

  • string TextBoxValueCSSView –> estilo del textbox de la edición.

Ejemplo:

[Localizable(true), Category(“Edit”)]
public string CancelImageUrl
{
get{
if (ViewState[“CancelImageUrl”] != null)
return ViewState[“CancelImageUrl”].ToString();
else
return “”;
}
set{
ViewState[“CancelImageUrl”] = value;
}
}

Ahora veremos realmente donde se encuentra la chica del control y eso es en el evento RenderPostText que es que se lanza justo después de pintar el nodo y nos servirá para pintar los controles de edición justo cuando termina el nodo.

protected override void RenderPostText(HtmlTextWriter writer)

if (Editable)
{
#region Variables

this.SelectAction = TreeNodeSelectAction.Select;
string idEdit = Guid.NewGuid().ToString();
string idView = Guid.NewGuid().ToString();
string idTb = Guid.NewGuid().ToString();
Page page = HttpContext.Current.CurrentHandler as Page;

#endregion Variables

#region script

if (page == null)
throw new NotSupportedException(“Error”);

#endregion script


Primero comprobamos si el nodo está habilitado para ser editado y luego inicializamos los identificadores que posteriormente necesitaremos para localizar los controles que utilizaremos para la edición del nodo.


Otra parte importante del código es que como no podemos acceder directamente a la página desde un nodo del TreeView, la tenemos que recuperar del contexto actual.




  • Panel Modo Vista: crearemos un panel que contendrá los controles que mostrarán los datos en modo vista, una label para mostrar los datos, la imagen para habilitar la edición la cual si no se informa utilizaremos una que tenemos guardada en los recursos del ensamblado y finalmente le añadiremos el evento onclick de cliente para lanzar la edición desde javascript (editNode).


#region Panel modo Vista

writer.AddAttribute(“id”, idView);
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, “inline”);
writer.RenderBeginTag(HtmlTextWriterTag.Div);

Label lb = new Label();
lb.CssClass = this.TextBoxValueCSSView;
lb.Text = string.Format(“({0})”, TextBoxValue);
lb.RenderControl(writer);

writer.Write(” “);

Image imgV = new Image();
if (!string.IsNullOrEmpty(EditImageUrl))
imgV.ImageUrl = EditImageUrl;
else
imgV.ImageUrl = page.ClientScript.GetWebResourceUrl(this.GetType(), “TreeviewEditControl.Resources.ItemEdit.gif”);
imgV.Attributes.Add(“onclick”, “editNode( ‘” + idEdit + “‘, ‘” + idView + “‘)”);
imgV.Style.Add(HtmlTextWriterStyle.Cursor, “Pointer”);
imgV.ImageAlign = ImageAlign.Middle;
imgV.ToolTip = this.EditTooltip;
imgV.RenderControl(writer);

writer.Write(” “);

writer.RenderEndTag();

#endregion Panel modo Vista




  • Panel Modo Edición: crearemos otro panel para mostrar los controles cuando el nodo esté en edición. Un textBox para insertar los datos y dos imageButtons. Una para guardar los datos y otra para anular la edición. Igual que anteriormente le añadiremos el evento onclick para las acciones desde javascript ( viewNode, cancelNode).

 


writer.AddStyleAttribute(HtmlTextWriterStyle.Display, “none”);
writer.AddAttribute(“id”, idEdit);
writer.RenderBeginTag(HtmlTextWriterTag.Div);

TextBox tb = new TextBox();
tb.Text = TextBoxValue;
tb.ID = idTb;
tb.Width = Unit.Pixel(40);
tb.RenderControl(writer);

writer.Write(” “);

ImageButton imgE = new ImageButton();
if (!string.IsNullOrEmpty(SaveImageUrl))
imgE.ImageUrl = SaveImageUrl;
else
imgE.ImageUrl = page.ClientScript.GetWebResourceUrl(this.GetType(), “TreeviewEditControl.Resources.disk_blue.gif”);

imgE.OnClientClick = “viewNode(‘” + _owner.ClientID + “‘, ‘” + idTb + “‘,’EditNode|” + this.ValuePath + “‘)”;
imgE.ImageAlign = ImageAlign.Middle;
imgE.ToolTip = this.SaveTooltip;
imgE.RenderControl(writer);

writer.Write(” “);

//Imagen para cancelar
Image imgC = new Image();
if (!string.IsNullOrEmpty(CancelImageUrl))
imgC.ImageUrl = CancelImageUrl;
else …


Otra de las cosas que tenemos que tener muy encuenta es guardar correctamente el viewState del control. Para eso las propiedades públicas las vamos guardando en una variable privada que es un StateBag ( guarda el stado de vista de los controles Asp.net ).


Luego cuando el control guarda el viewState utilizaremos la clase Pair para guardar el estado de las propiedades base del control y las nuevas propiedades que nosotros hemos generado. Y al recuperar el estado actuamos a la inversa para que de esta manera se mantenga es estado completo del control.


StateBag _viewState;

private StateBag ViewState
{
get{
if (this._viewState == null)
{
this._viewState = new StateBag();
if (!((IStateManager)this._viewState).IsTrackingViewState)
((IStateManager)this._viewState).TrackViewState();
}
return this._viewState;
}
}

protected override object SaveViewState()
{
Pair state = new Pair();
state.First = base.SaveViewState();
if (this._viewState != null)
state.Second = ((IStateManager)this._viewState).SaveViewState();
return state;
}

protected override void LoadViewState(object state)
{
if (state == null)
base.LoadViewState(state);
else
{
Pair p = (Pair)state;
base.LoadViewState(p.First);
((IStateManager)this.ViewState).LoadViewState(p.Second);
}
}


Para finalizar con la generación de este control solo nos faltaría destacar los recursos embebidos como las imágenes y el fichero Javascript


[assembly: System.Web.UI.WebResource(“TreeviewEditControl.Resources.disk_blue.gif”, “img/gif”)]
[assembly: System.Web.UI.WebResource(“TreeviewEditControl.Resources.disk_blue_error.gif”, “img/gif”)]
[assembly: System.Web.UI.WebResource(“TreeviewEditControl.Resources.ItemEdit.gif”, “img/gif”)]
namespace TreeviewEditControl

La función más importante del fichero javascript es la que genera el postback al servidor y envía el identificador del control y una array de argumentos que utilizaremos para recuperar los datos del nodo editado.


function viewNode( control, txtID, args )
{
var txt = document.getElementById( txtID );
if( txt != null)
__doPostBack( control, args + “|” + txt.value );

}


Una vez finalizado el control lo utilizaremos en una página web y podemos recuperar los datos con el evento que creamos en el TreeView.


protected void TreeViewEdit1_TreeNodeEdit(object sender, TreeNodeEditEventArgs e)
{
//Guardar Datos
bool check = e.Checked;
string Nombre = e.NodoText;
string ID = e.NodoValue;
string valorInicial = e.OldValue;
string nuevoValor = e.NewValue;
}

 


Bueno yo creo que ya ha quedado claro como se ha creado el control, si tenéis dudas y queréis probar el código os lo dejo para que os lo podáis bajar.


 


Cross-Posting desde http://lonetcamp.com


 


 

[Asp.net] Editable Treeview I

En más de una ocasión nos ha sido de mucha utilidad un control del tipo TreeView para mostrar una jerarquía de datos, pero el control se nos puede quedar un poco limitado cuando pretendemos interactuar con los datos.


Por ese motivo he creado un control TreeView con nodos editables, y el resultado final es como este:


 


Comenzaremos creando un proyecto de librerías de clase para albergar nuestro control, a la clase le llamaremos TreeViewEdit y heredaremos de System.Web.UI.WebControls.TreeView.

[ToolboxData(“<{0}:TreeViewEdit runat=server></{0}:TreeViewEdit>”)]
public class TreeViewEdit : TreeView

Realmente toda la potencia del control no se encuentra en el TreeView, sino en los Nodos que le daremos la posibilidad de ser editados. En esta clase lo único que tenemos que hacer es un nuevo evento para capturar la información modificada del nodo.


Para eso crearemos un nuevo evento llamado TreeNodeEdit.

[Category(“Data”)]
public event TreeNodeEditEventHandler TreeNodeEdit;
protected virtual void OnTreeNodeEdit(TreeNodeEditEventArgs e)
{
if (TreeNodeEdit != null)
{
TreeNodeEdit(this, e);
}
}

Si os fijáis nuestro evento se basa en un delegado personalizado TreeNodeEditEventHandler y TreeNodeEditEventArgs para customizar el conjunto de argumentos que utilizaremos para devolver los datos del nodo modificado.


El delegado:

public delegate void TreeNodeEditEventHandler(object sender, TreeNodeEditEventArgs e);

La clase que utilizaremos para nuestros argumentos:

public class TreeNodeEditEventArgs : System.EventArgs
{
#region Variables

private string _nodoText;
private string _nodoValue;
private string _oldValue;
private string _newValue;
private bool _checked;

#endregion Variables

#region Propiedades

public string NodoText { get { return _nodoText; } }
public string NodoValue { get { return _nodoValue; } }
public string OldValue { get { return _oldValue; } }
public string NewValue { get { return _newValue; } }
public bool Checked { get { return _checked; } }

#endregion Propiedades

#region Constructor

public TreeNodeEditEventArgs(string nodotext, string nodoValue,
string oldValue, string newValue, bool check)
{
this._nodoText = nodotext;
this._nodoValue = nodoValue;
this._oldValue = oldValue;
this._newValue = newValue;
this._checked = check;
}

#endregion Constructor
}


Gracias a esta clase cuando consumamos el evento del TreeView podremos recuperar los datos:

  bool Check = e.Checked;
string Nombre = e.NodoText;
string ID = e.NodoValue;
string valorInicial = e.OldValue;
string NuevoValor = e.NewValue;

Finalmente para tener finalizada la primera parte del control tan solo nos queda sobrescribir dos eventos:




  • RaisePostBackEvent para procesar los eventos procesados por el control al enviar los datos al servidor.
protected override void RaisePostBackEvent(string eventArgument)
{
base.RaisePostBackEvent(eventArgument);

string[] args = eventArgument.Split(‘|’);
if (args.Length > 0)
{
if (args[0] == “EditNode”)
{
TreeNodeEdit node = (TreeNodeEdit)this.FindNode(args[1].ToString());

TreeNodeEditEventArgs arg = new TreeNodeEditEventArgs(node.Text,
node.Value,
node.OldValue,
args[2].ToString(),
node.Checked);

//Guardamos la modificación en el estado del control y lanzamos el evento correcto
node.TextBoxValue = args[2].ToString();
OnTreeNodeEdit(arg);
}
}
}


Esperamos una colección de argumentos separado por el caracter ‘|’ que envía el cliente al lanzar el postback.




  1. Comprobamos que los argumentos que esperamos son realmente de edición (args[0] == “EditNode”)


  2. El segundo argumento es el Path del nodo que hemos editado.


  3. Creamos un TreeNodeEditEventArgs con los datos recuperados del nodo.


  4. Invocamos el evento TreeNodeEdit a través del método OnTreeNodeEdit, con el argumento correctamente rellenado para que quien consuma nuestro evento pueda interactuar con los datos modificados.


  • OnPreRender para registrar el fichero Javascript que utilizaremos como recurso incrustado y darle una funcionalidad más ligera al interactuar con el cliente.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
this.Page.ClientScript.RegisterClientScriptResource(GetType(), “TreeviewEditControl.Resources.JS.js”);
}

Me parece que para ser la primera parte es suficiente, en el próximo artículo entraremos a fondo con la clase TreeNodeEdit que es la clase que representan los nodos del TreeView.


Cross-Posting desde http://lonetcamp.com


 


 

Extender una propiedad de un ServerControl

Hoy una consulta en el foro MSDN me ha parecido muy interesante y por ese motivo y porque la explicación es un poco larga, describiré más detalladamente como poder hacer lo que Roberto Corona necesita.

http://forums.microsoft.com/MSDN-ES/ShowPost.aspx?PostID=3843776&SiteID=11

 En resumen Roberto está creando un control de servidor del cual pretende que una propiedad muestre los botones que se encuentren en el formulario para poderlo seleccionar, al etilo de un validador.

 

Para hacer esto crearé un proyecto web para probar el control y otro proyecto que será el propio control de servidor. La clase del control la llamaré ServerControl1.cs, ya lo sé, muy poco original !! 

El control es realmente sencillo:

Nuestro control heredará de WebControl y crearemos la propiedad ControlID para guardar el identificador del botón que queremos controlar 


[DefaultProperty("Text")] [ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")] public class ServerControl1 : WebControl { [DefaultValue(""), TypeConverter(typeof(ButtonConverter))] public string ControlID { get { object o = ViewState["ControlID"]; if (o == null) return String.Empty; return (string)o; } set { if (ControlID != value) ViewState["ControlID"] = value; } } protected override void RenderContents(HtmlTextWriter output) { if(String.IsNullOrEmpty(ControlID)) output.Write("Tienes que seleccionar un Botón"); else output.Write(ControlID); } }

Lo destacable de este código es la clase ButtonConverter, que es la que se encargará de devolvernos los controles button del formulario para poderlo elegir desde el control, esta clase esta basada en la clase ControlIDConverter.

http://msdn.microsoft.com/es-es/library/system.web.ui.webcontrols.controlidconverter(VS.80).aspx 

La clase ControlIDConverter se deriva de la clase StringConverter y proporciona una lista de id. de control para su presentación en un control de cuadrícula de propiedades en entornos en tiempo de diseño. La clase ControlIDConverter también actúa como clase base para las clases AssociatedControlConverter y ValidatedControlConverter, que son los convertidores de tipos para los controles Web y los controles que admiten atributos de propiedades de validación, respectivamente.


class ButtonConverter : StringConverter

 


protected virtual bool FilterControl(Control control) private string[] GetControls(IDesignerHost host, object instance) { IContainer container = host.Container; IComponent component = instance as IComponent; if ((component != null) && (component.Site != null)) { container = component.Site.Container; } if (container == null) { return null; } ComponentCollection components = container.Components; ArrayList list = new ArrayList(); foreach (IComponent component2 in components) { Control control = component2 as Control; if(control.GetType().Name == typeof(Button).Name) { list.Add(control.ID); } } list.Sort(Comparer.Default); return (string[])list.ToArray(typeof(string)); } public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) public override bool GetStandardValuesSupported(ITypeDescriptorContext context)

 

 El método a destacar es GetControl que es el que recupera la lista de IDs de los botones y el efecto final es exactamente como el de ControlToValidate de los validadores de Asp.NET.

 

 Ahora ya tenemos nuestra propiedad extendida para utilizar nuestro control de la manera que más nos guste.

Cross-Posting de http://lonetcamp.com

 

Y ya van dos Errores graves de Chrome !!!

Desde ayer que me están bombardeando con el nuevo navegador de Google, lo has probado? lo has probado?.


Pues para demostrar que no todo en la programación no es ni blanco ni negro, aqui tenéis el primer agujero de seguridad y además es un fallo garrafal por dejadez.


Este nuevo e innovador navegador está basado en Webkit de Apple, pero no se han molestado ni en implementar el parche que el mismo Apple publico para resolver este problema de seguridad.


Y ya van dos…..

http://es.wikipedia.org/wiki/WebKit

Suerte que es una versión Beta. 😉


Nos vemos.


 

Asp.net PoPup sin JavaScript !!!

En ASP siempre que hemos querido abrir una nueva ventana desde un botón, imageButton, etc. Hemos tenido que echar mano de JavaScript para poder abrir un nuevo navegador.

Pero hay un truco que podemos utilizar directamente desde asp.net y que gracias a la propiedad Target del formulario podemos definir como queremos que se muestre la página web.


protected void Page_Load(object sender, EventArgs e) { if(!IsPostBack) this.Form.Target = "_blank"; }

 

 Para hacer la prueba hemos definido la propiedad Target del formulario como _blank  y cada vez que recargemos la página lo hará en una nueva ventana. Si le damos un par de vueltas a esta propiedad le podemos sacar mucho partido.

Otra manera de hacer lo mismo pero que solo afecte por ejemplo cuando hacemos click en un botón y no siempre que recargamos la página sería. 


protected void Page_Load(object sender, EventArgs e) { Button1.OnClientClick = "form1.target='_blank'"; Button1.PostBackUrl = "Ventana.aspx"; }

 Cuando carga la página definimos en la propiedad OnClientClick “define el evento click en el cliente antes de enviar la petición al servidor” que el formulario abrirá una nueva ventana y en la propiedad PostBackUrl  definimos a que dirección se redirigirá después de hacer el recarga la página.

 Teniendo todo esto en cuenta porque no creamos un método en nuestra clase base para poder decidir si nuestros controles de servidor actúen de forma normal o abran una página nueva.

Para hacer esto posible crearemos un método genérico con tres parámetros.

  1. control: el control a personalizar.
  2. url: la dirección a donde redirigiremos.
  3. target: Una enumeración con las diferentes opciones que acepta la propiedad Target. 

private void DestinoLink<T>( ref T control, string url, Target target ) { switch (control.GetType().Name) { case "Button": case "LinkButton": case "ImageButton": control.GetType().GetProperty("OnClientClick").SetValue(control, this.form1.Name + ".target='_blank'", null); control.GetType().GetProperty("PostBackUrl").SetValue(control, url, null); break; case "HyperLink": control.GetType().GetProperty("Target").SetValue(control, this.form1.Name + ".target='_blank'", null); control.GetType().GetProperty("NavigateUrl").SetValue(control, url, null); break; } } /// <summary> /// Con el uso de Target indicamos al enlace donde tiene que abrirse. /// </summary> enum Target { _blank, _top, _self, _parent }

 

 Gracias a los genéricos informamos del tipo del control a personalizar y dependiendo del tipo que detectemos utilizaremos reflexion para definir sus propiedades. De esta manera independientemente de que el control sea un botón o un link podemos utilizar el método de la misma manera.

Para probar el código he creado dos páginas; una con un button, un linkButton y un hyperlink llamada “default.aspx” y otra con un texto llamada “ventana.aspx”.


protected void Page_Load(object sender, EventArgs e) { DestinoLink<Button>(ref Button1, "Ventana.aspx", Target._blank); DestinoLink<HyperLink>(ref HyperLink1, "Ventana.aspx", Target._blank); DestinoLink<LinkButton>(ref LinkButton1, "Ventana.aspx", Target._blank); }

 De esta manera tan sencilla podemos preparar los controles de servidor para que habran una nueva ventana.

  

Espero que esta entrada os haya parecido interesante.

Nos vemos.

Cross-posting de http://lonetcamp.com