Custom Editor Parts...
A new .NET 2.0 feature, web parts, provides a portal infrastructure to .NET applications. You can edit Web Parts dynamically with Custom Editor Parts.
The new feature, web parts, provides a portal infrastructure to .NET applications. Web
parts can be added, removed, and reordered, while retaining all of these settings using the
personalization API. This feature is a tremendous feature to add to the framework, especially
since web parts are customizable (i.e., you can write custom web parts by inheriting from
the System.Web.UI.WebControls.WebParts.WebPart class). You render a web part with the same
features as a custom control, by using the CreateChildControls or Render method.
If you've read my example on IRepeatInfoUser, I’ve created a class that iteratively creates
a series of tables, in some sequential order. So the control can render items horizontally,
vertically, can create a table (for example, a 4x3 or 2x6 table), etc. This behavior is
controlled by three properties: count (total number of items in a vertical or horizontal
direction), direction (an enumeration stating the direction to repeat in), and layout (render
in a table format or in a flow format).
I've changed this NewsRepeater control to inherit from WebPart, and exposed these three
properties to a custom editor part I built (NewsEditor). Let's start by looking at the new
properties.
|
private int _count = 0; [ Personalizable(true), WebBrowsable(true), WebDisplayName("Repeat Count") ] public int Count { get { return _count; } set { _count = value; } } private RepeatDirection _dir = RepeatDirection.Horizontal; [ Personalizable(true), WebBrowsable(true), WebDisplayName("Repeat Direction") ] public RepeatDirection Direction { get { return _dir; } set { _dir = value; } } private RepeatLayout _layout = RepeatLayout.Table; [ Personalizable(true), WebBrowsable(true), WebDisplayName("Repeat Layout") ] public RepeatLayout Layout { get { return _layout; } set { _layout = value; } } |
These properties all inherit the same attributes. Personalizable is the one that must be
mentioned in this article (the other two will be discussed in a separate article). This
attribute declares that the property for the control can have its value retained by the
Personalization API, and retrieved for later purposes.
Our custom editor part implements an ApplyChanges and SyncChanges method that changes these
values based on the editor. The controls used to edit the values are referenced as private
variables and instantiated in CreateChildControls (shown later). In ApplyChanges, the web
part (NewsRepeater) gets its values assigned from the values in the custom control.
SyncChanges goes in the opposite direction.
|
public class NewsEditor : EditorPart { private TextBox _count; private DropDownList _direction; private RadioButtonList _layout; public override bool ApplyChanges() { NewsRepeater part = this.WebPartToEdit as NewsRepeater; if (part != null) { this.EnsureChildControls(); part.Count = int.Parse(_count.Text); part.Direction = (RepeatDirection)Enum.Parse(typeof(RepeatDirection), _direction.SelectedValue); part.Layout = (RepeatLayout)Enum.Parse(typeof(RepeatLayout), _layout.SelectedValue); } return (part != null); } public override void SyncChanges() { NewsRepeater part = this.WebPartToEdit as NewsRepeater; if (part != null) { this.EnsureChildControls(); _count.Text = part.Count.ToString(); _direction.SelectedValue = part.Direction.ToString(); _layout.SelectedValue = part.Layout.ToString(); } } } |
There is a possibility that the editor part is editing another type of web part, and thus, the null check must be applied to ensure we are editing the correct web part type. In addition, EnsureChildControls must be called so the controls exist to pass or retrieve the values from. The CreateChildControls method instantiates the custom control used in our editor part, and the Render method renders it in a table format, just like any other control.
|
protected override void CreateChildControls() { this._count = new TextBox(); this.Controls.Add(_count); string[] items = Enum.GetNames(typeof(RepeatDirection)); this._direction = new DropDownList(); this.Controls.Add(_direction); foreach (string item in items) { this._direction.Items.Add(new ListItem(item, item)); } if (_direction.Items.Count > 0) _direction.SelectedIndex = 0; items = Enum.GetNames(typeof(RepeatLayout)); this._layout = new RadioButtonList(); this.Controls.Add(_layout); foreach (string item in items) { this._layout.Items.Add(new ListItem(item, item)); } if (_layout.Items.Count > 0) _layout.SelectedIndex = 0; } protected override void Render(HtmlTextWriter writer) { writer.RenderBeginTag(HtmlTextWriterTag.Table); writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write("Count"); writer.RenderEndTag(); writer.RenderBeginTag(HtmlTextWriterTag.Td); _count.RenderControl(writer); writer.RenderEndTag(); writer.RenderEndTag(); writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write("Direction"); writer.RenderEndTag(); writer.RenderBeginTag(HtmlTextWriterTag.Td); _direction.RenderControl(writer); writer.RenderEndTag(); writer.RenderEndTag(); writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write("Layout"); writer.RenderEndTag(); writer.RenderBeginTag(HtmlTextWriterTag.Td); _layout.RenderControl(writer); writer.RenderEndTag(); writer.RenderEndTag(); writer.RenderEndTag(); } |
To use this example, click the Edit link at the bottom. This invokes edit mode for all web parts. Then click edit for the web part (upper-right hand corner) to edit the web part, which will invoke the editor. Select some new properties and click OK or Apply.