Hoy mostraré un ejemplo de cómo escribir un Custom Editor Part para una webpart de SharePoint, en realidad esto no tiene mucha ciencia si no es por el hecho de que utilizaré Silverlight(como siempre) para crear Editor Parts, con una experiencia rica al usuario final.
Creación de la webpart
Primero crearé una simple webpart, llamada SampleWebPart, con un control Label, que tendrá el valor del color actual del fondo en formato hexadecimal.
Crear una clase que herede de EditorPart, que se encuentra definido dentro del namespace System.Web.UI.WebControls.WebParts, para este ejemplo crearé una clase llamada ColorEditor, que servirá para editar la propiedad BackColor de SampleWebPart. BackColor es una propiedad que sobrescribiré, ya que esta es una propiedad heredada, y solo le estoy agregando el custom Editor Part. A Continuación el código de la clase ColorEditor.cs:
using System; using System.Collections.Generic; using System.Text; using System.Web.UI.WebControls.WebParts; using System.Web.UI.WebControls; using System.Drawing; using System.Web.UI.SilverlightControls; namespace Blog.Webparts.WebPartCode { public class ColorEditor : EditorPart { HiddenField hiddenField; public override bool ApplyChanges() { this.EnsureChildControls(); SampleWebpart s = (SampleWebpart)this.WebPartToEdit; //obtenemos el valor del hidden control string strcolor = hiddenField.Value; Color c = Color.Transparent.FromHex(strcolor); s.BackColor = c; return true; } public override void SyncChanges() { this.EnsureChildControls(); SampleWebpart s = (SampleWebpart)this.WebPartToEdit; Color c = s.BackColor; hiddenField.Value = c.ToHex(); } protected override void CreateChildControls() { base.CreateChildControls(); try { hiddenField = new HiddenField(); hiddenField.ID = "hfcolorPicker"; base.Controls.Add(hiddenField); Silverlight slControl = new Silverlight(); slControl.ID = "slColorPicker"; slControl.InitParameters = "controlid=" + hiddenField.ClientID; slControl.Source = "/ClientBin/ColorPickerEditor.xap"; slControl.Width = 300; slControl.Height = 250; slControl.MinimumVersion = "2.0.31005.0"; slControl.Windowless = true; base.Controls.Add(slControl); } catch(Exception ex) { } } } }
En esencia, la creación de un custom editor part, es muy parecida a la creación de una webpart, ya que podemos sobreescribir el método CreateChildControls para agregar los controles que conformarán el editor. Pero además, se heredan dos métodos abstractos que deben ser implementados, SyncChanges y ApplyChanges etc
El método SyncChanges
Este método, tomara los valores actuales de la webpart y los establecera a los controles de el custom editor. Cuando se carga el custom editor, este método es el primero que se ejecuta, no el OnLoad, ni el CreateChildControls (por eso se debe hacer una llamada a EnsurechildControls al inicio de este método)
El método ApplyChanges
Este método se encargara de reflejar los valores establecidos en el custom editor a nuestra webpart target.
Para hacer referencia a la webpart de la cual estamos leyendo/escribiendo valores, lo hacemos mediante la propiedad WebPartToEdit.
El método CreateChildControls
Es en este método donde se crean los controles que conformarán la interfaz del custom editor part, como se observa en el siguiente snippet, he instanciado un objeto de la clase Silverlight, que se encuentra en el namespace System.Web.UI.SilverlightControls, que es la que nos permite renderear objetos silverlight en el cliente, solo estableciendo unas cuantas propiedades. Además he agregado un control HiddenField, que utilizaré como medio de comunicación entre el código silverlight y la clase ColorEditor.cs
El control ColorPicker es totalmente una creación de Matthias Shapiro, de su post Final-ish Silverlight Color Picker Utility, y que muy amablemente puso a disposición de la comunidad. Many thanks Matthias!. Yo solo he modificado la página contenedora de este control, para que acepte como parámetro el id del hidden field y así guardar el valor del color establecido a través del color picker.
Sobrescribir el método CreateEditorParts dentro de la clase SampleWebPart, lo anterior, para instruir a WSS a que cargue nuestro custom editor part además de los Editor Parts estándar que son normalmente desplegados en el Tool Panel. En esta parte utilizamos colecciones de tipo EditorPartCollection. Como se observa en el código siguiente, debemos agregar todos los custom editor parts a la colección de la clase base para crear una nueva instancia de EditorPartCollection.
Es importante establecer la propiedad ID del los objetos de tipo EditorPart, de lo contrario obtendremos errores al intentar ejecutar nuestro código.
public override EditorPartCollection CreateEditorParts() { List<Editorpart> editor = new List<Editorpart>(); EditorPart ep = new Blog.Webparts.WebPartCode.ColorEditor(); ep.ID = this.ID + "_ColorEditor"; editor.Add(ep); EditorPartCollection baseEditors = base.CreateEditorParts(); return new EditorPartCollection(baseEditors, editor ); }
Al final podremos observar como la experiencia de usuario se ve bastante enriquecida al usar tecnologías como Silverlight.
Por último, el codigo completo de la clase SampleWebPart
De aquí pueden descargar el codigo completo
Happy Coding!
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Web.UI; using System.Web.UI.WebControls.WebParts; using System.Web.UI.WebControls; using System.Drawing; using System.ComponentModel; using System.Drawing.Design; using Blog.Webparts.WebPartCode; namespace Blog.Webparts { [Guid("057b92f2-193e-4ac4-ba28-bf06e6180aa2")] public class SampleWebpart : Microsoft.SharePoint.WebPartPages.WebPart, IWebEditable { private bool _error = false; Label lbl1; [Personalizable(PersonalizationScope.Shared)] [WebBrowsable(false)] [WebDisplayName("Color de fondo")] [WebDescription("Color de fondo")] [DefaultValue(typeof(Color), "Red")] public override Color BackColor { get { return base.BackColor; } set { base.BackColor = value; } } public SampleWebpart() { this.ExportMode = WebPartExportMode.All; } ////// Create all your controls here for rendering. /// Try to avoid using the RenderWebPart() method. /// protected override void CreateChildControls() { if (!_error) { try { base.CreateChildControls(); lbl1 = new Label(); lbl1.ID = "lblInitialDate"; lbl1.Width = 300; lbl1.Text = "Label con texto"; lbl1.Font.Size = new FontUnit(24); this.Controls.Add(lbl1); this.Controls.Add(new LiteralControl(" ")); this.Controls.Add(new LiteralControl(" ")); this.Height = "200"; } catch (Exception ex) { HandleException(ex); } } } protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); lbl1.Text = this.BackColor.ToHex(); } public override EditorPartCollection CreateEditorParts() { List<Editorpart> editor = new List<Editorpart>(); EditorPart ep = new Blog.Webparts.WebPartCode.ColorEditor(); ep.ID = this.ID + "_ColorEditor"; editor.Add(ep); EditorPartCollection baseEditors = base.CreateEditorParts(); return new EditorPartCollection(baseEditors, editor ); } ////// Ensures that the CreateChildControls() is called before events. /// Use CreateChildControls() to create your controls. /// protected override void OnLoad(EventArgs e) { if (!_error) { try { base.OnLoad(e); this.EnsureChildControls(); ScriptManager sm = ScriptManager.GetCurrent(this.Page); if (sm == null) { sm = new ScriptManager(); this.Controls.AddAt(0,sm); } } catch (Exception ex) { HandleException(ex); } } } ////// Clear all child controls and add an error message for display. /// private void HandleException(Exception ex) { this._error = true; this.Controls.Clear(); this.Controls.Add(new LiteralControl(ex.Message)); } } }
De aquí pueden descargar el codigo completo
Happy Coding!