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.
Alguna Opcion de descarga?
Ya replique los pasos comentados pero Tengo algunos problemillas.