Extend EPiServer XForm
There are lot of times you want to extend the XForm. It’s one of the most hardest part of EPiServer to extend to your need, since none of the items you can add inside a xform is hardcoded inside the edit mark-up. You can make your own validation and attach to these events
control.BeforeLoadingForm +=control.ControlsCreated +=
control.BeforeSubmitPostedData +=
control.AfterSubmitPostedData +=
But if you want to make the choices inside a dropdown list come from the category tree or the page tree you have to make your own logic.
I have done this in some projects, but I think this code is a cool way of extending, since it’s very plug and play :)
will be rendered like this:
First a made a interface that my extension classes can use. I’m marking them with GuiPlugIn so I can turn them on and off from the Plug-In Managers. More about this method in my presentation on EPiServer meetup in Norway page 40.
public interface ICanExtendXform
{
void DisplayHelp(Dictionary<string, StringBuilder> help);
void ExtendItem(XFormControlBase item, StringBuilder debug);
}
Then I attached to the start event (page 24 same presentasjon).
public class AttachEvents : PlugInAttribute
{
public static List<ICanExtendXform> Handlers { get; set; }
public static void Start()
{
XFormControl.ControlSetup += new EventHandler(XFormControl_ControlSetup);
PageBase.PageSetup += new PageSetupEventHandler(PageBase_PageSetup);
var list=FindPlugIns(typeof(ICanExtendXform).Name,null);
Handlers=new List<ICanExtendXform>();
foreach (var item in list)
Handlers.Add(item.Create() as ICanExtendXform);
}
static void PageBase_PageSetup(PageBase sender, PageSetupEventArgs e)
{
if (sender is EPiServer.UI.Edit.XFormEdit)
sender.PreRender += new EventHandler(EditXform_PreRender);
}
static void XFormControl_ControlSetup(object sender, EventArgs e)
{
XFormControl control = (XFormControl)sender;
control.ControlsCreated += new EventHandler(control_ControlsCreated);
}
I use the PageBase.PageSetup to extend the edit mode of the xform page.The actually change does I like this
static void EditXform_PreRender(object sender, EventArgs e)
{
Control ctr = FindControl<Panel>(sender as Control, "PropertiesArea");
if (ctr != null)
{
Dictionary<string, StringBuilder> help = new Dictionary<string, StringBuilder>();
foreach (var item in Handlers)
{
item.DisplayHelp(help);
}
StringBuilder help2 = new StringBuilder();
foreach (string key in help.Keys)
{
help2.Append("<h3>" + key + "</h3><ul>");
help2.Append(help[key]);
help2.Append("</ul>");
}
ctr.Controls.Add(new Literal() { Text = help2.ToString(), EnableViewState = false });
}
}
This will add the help text inside the edit page of a form
My extensions are made in separate classes all tagged with a interface and the GuiPlugIn so they can be turn on and off
[GuiPlugIn]
public class ExtendXformWithCssClass : ICanExtendXform
{
public void DisplayHelp(Dictionary<string, StringBuilder> help)
{
if (!help.ContainsKey("CssClass"))
help.Add("CssClass", new StringBuilder());
help["CssClass"].Append("<li><strong>readonly</strong> inside cssclass will make it readonly</li>");
}
public void ExtendItem(XFormControlBase item, StringBuilder debug)
{
if (item.Attributes["class"] != null && item.Attributes["class"].Contains("readonly"))
item.Attributes.Add("readonly", "true");
}
}
[GuiPlugIn]
public class ExtendXformWithPageData:ICanExtendXform
{
public void DisplayHelp(Dictionary<string,StringBuilder> help)
{
if (!help.ContainsKey("Choices"))
help.Add("Choices",new StringBuilder());
help["Choices"].Append("<li><strong>EPiChildren_3</strong> in Name value will be replaced with all children of page 3</li>");
}
public void ExtendItem(XFormControlBase item,StringBuilder debug)
{
ReplaceChoicesWith_EPiChildren_(item, debug);
}
#region ReplaceChoicesWith_EPiChildren_
private static void ReplaceChoicesWith_EPiChildren_(XFormControlBase item, StringBuilder debug)
{
SelectControl select = item as SelectControl;
if (select != null)
{
for (int i = 0; i < select.Choices.Count(); i++)
{
string val = select.Choices[i].Label;
if (val.StartsWith("EPiChildren_"))
{
debug.Append("<dir>Found option " + i + " with " + val);
string[] s = val.Split("_".ToCharArray());
PageDataCollection pages = EPiServer.DataFactory.Instance.GetChildren(PageReference.Parse(s[1]));
debug.Append(" getting " + pages.Count + " pages");
select.Choices.Remove(select.Choices[i]);
foreach (PageData page in pages)
{
select.Choices.Insert(i, new SelectItem() { Value = page.PageLink.ToString(), Label = page.PageName });
i++;
}
debug.Append("</dir>");
}
}
}
}
#endregion
}
[GuiPlugIn]
public class ExtendXformWithCategory : ICanExtendXform
{
public void DisplayHelp(Dictionary<string,StringBuilder> help)
{
if (!help.ContainsKey("Choices"))
help.Add("Choices",new StringBuilder());
help["Choices"].Append("<li><strong>EPiCategory_News</strong> in Name value will be replaced with all children of category News</li>");
}
public void ExtendItem(XFormControlBase item, StringBuilder debug)
{
ReplaceChoicesWith_EPiCategory_(item, debug);
}
#region ReplaceChoicesWith_EPiCategory_
private static void ReplaceChoicesWith_EPiCategory_(XFormControlBase item, StringBuilder debug)
{
SelectControl select = item as SelectControl;
if (select != null)
{
for (int i = 0; i < select.Choices.Count(); i++)
{
string val = select.Choices[i].Label;
if (val.StartsWith("EPiCategory_"))
{
debug.Append("<dir>Found option " + i + " with " + val);
string[] s = val.Split("_".ToCharArray());
Category cat = EPiServer.DataAbstraction.Category.Find(s[1]);
if (cat != null)
{
debug.Append(" found category and using children:"+cat.Categories.Count);
select.Choices.Remove(select.Choices[i]);
foreach (Category subCat in cat.Categories)
{
select.Choices.Insert(i, new SelectItem() { Value = subCat.ID.ToString(), Label = subCat.LocalizedDescription });
i++;
}
}
debug.Append("</dir>");
}
}
}
}
#endregion
}
[GuiPlugIn]
public class ExtendXformWithUserData : ICanExtendXform
{
string Key="EPiUserData_";
public void DisplayHelp(Dictionary<string,StringBuilder> help)
{
if (!help.ContainsKey("Text in TextBox"))
help.Add("Text in TextBox",new StringBuilder());
help["Text in TextBox"].Append("<li><strong>EPiUserData_UserName</strong> will be replaced with Current users UserName</li>");
help["Text in TextBox"].Append("<li><strong>EPiUserData_Email</strong> will be replaced with Current users Email</li>");
help["Text in TextBox"].Append("<li><strong>EPiUserData_Company</strong> will be replaced with Current users Company</li>");
}
public void ExtendItem(XFormControlBase item, StringBuilder debug)
{
if (item.Value != null && item.Value.StartsWith(Key))
{
string rest = item.Value.Substring(Key.Length);
if (rest == "UserName")
item.Value = EPiServerProfile.Current.UserName;
else
{
object val = null;
if (EPiServerProfile.Current.TryGetProfileValue(rest, out val))
item.Value = val.ToString();
}
}
}
}
That's all. And easy way of changing parts of XForm and make some code pluggable :)
My presentasjon at EPiServer meetup in Norway is here
Looking forward the EPiServer Partner Summit
Comments