Anders Hattestad
Nov 3, 2008
(0 votes)

XForm as Dynamic Content

Have played a little with xform elements as dynamic content. I first made some small changes to the  User Control as Property code. The result was that every User Control that can be used as a property now can be selected as a dynamic content.

The actually implementation used the property as base and added it self to the Property list Properties. There are two thing that are important. First make sure that the state is saved in a format that the dynamic content value can handle. Then make sure that the ID you are using in the inner property is unique. My solution was to take the GetHashCode of the State object. That is unique for all items that have differnt state.

The Itera.MultiProperty is also changed.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Web;
   4:  using Itera.Examples.Property;
   5:  using EPiServer.Core;
   6:  using System.Web.UI;
   7:  using EPiServer.Core.Transfer;
   9:  namespace Itera.DynamicContent
  10:  {
  11:      public class DynamicUserControlSelector : PropertyUserControlSelector, EPiServer.DynamicContent.IDynamicContent, IReferenceMap
  12:      {
  13:          #region IDynamicContent Members
  14:          PropertyDataCollection _properties;
  15:          public EPiServer.Core.PropertyDataCollection Properties
  16:          {
  17:              get
  18:              {
  19:                  if (_properties == null)
  20:                  {
  21:                      _properties = new PropertyDataCollection();
  22:                      _properties.Add("UserControl", this);
  23:                  }
  24:                  return _properties;
  25:              }
  26:          }
  27:          public System.Web.UI.Control GetControl(EPiServer.PageBase hostPage)
  28:          {
  29:              IPropertyControl result = CreatePropertyControl();
  30:              result.Properties = this.PropertyCollection;
  31:              result.PropertyData = this;
  32:              (result as Control).ID = StateAsID;// "ID" + this.State.GetHashCode(); //"UserControl" + Properties["HiddenName"].ToString();
  33:              return result as Control;
  34:          }
  35:          public bool RendersWithControl
  36:          {
  37:              get { return true; }
  38:          }
  41:          public string Render(EPiServer.PageBase hostPage)
  42:          {
  43:              throw new NotImplementedException();
  44:          }
  46:          public string StateAsID
  47:          {
  48:              get
  49:              {
  50:                  if (_state != null)
  51:                      return "state" + Math.Abs(_state.GetHashCode());
  52:                  return "statenull";
  53:              }
  54:          }
  56:          #region State (64 encoded)
  57:          string _state = null;
  58:          public string State
  59:          {
  60:              get
  61:              {
  62:                  if (Value == null)
  63:                      return null;
  64:                  return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes((string)Value));
  66:              }
  67:              set
  68:              {
  69:                  if (value != null)
  70:                  {
  71:                      _state = value;
  72:                      byte[] toDecodeByte = Convert.FromBase64String(value);
  74:                      System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
  75:                      System.Text.Decoder utf8Decode = encoder.GetDecoder();
  77:                      int charCount = utf8Decode.GetCharCount(toDecodeByte, 0, toDecodeByte.Length);
  79:                      char[] decodedChar = new char[charCount];
  80:                      utf8Decode.GetChars(toDecodeByte, 0, toDecodeByte.Length, decodedChar, 0);
  81:                      string result = new String(decodedChar);
  82:                      Value = result;
  84:                  }
  85:              }
  86:          }
  87:          #endregion
  89:          #endregion
  91:          #region IReferenceMap Members
  93:          IList<Guid> IReferenceMap.ReferencedPermanentLinkIds
  94:          {
  95:              get
  96:              {
  97:                  PropertyDataCollection props = base.ActiveDataCollection;
  98:                  List<Guid> list = new List<Guid>();
  99:                  base.FindGuids(props, list);
 100:                  return list;
 101:              }
 102:          }
 104:          void IReferenceMap.RemapPermanentLinkReferences(IDictionary<Guid, Guid> idMap)
 105:          {
 106:              base.RemapPermanentLinkReferences(idMap);
 107:          }
 109:          #endregion
 110:      }
 111:  }

But the xform have some other issues. When you have selected a xform on a page there will appear a new tab "Form Data". In that tab you can display all posts on that page, and also all post on pages that have the same form.

The problem is that if you either select the xform property (build in property selector) or the new constructions User Control as dynamic content that tab will not appear. With Reflector I looked around and the problem is three fold.

1) Getting the tab to be shown

The class XFormPostings ICustomPlugInLoader interface only check the current pages properties. That can easy be solved with making your own class that returns

new PlugInDescriptor[] { PlugInDescriptor.Load(typeof(XFormPostings)) };

if the User Control as Property or Dynamic content includes a xform.

Actually the implementation of the PropertyXhtmlString in CMS 5 R2 is pretty cool. You can loop over the fragments of the content and get the IStringFragment interface for each element. I missed thou a method for getting the inner "property" of the fragment. since I would like to loop thru the inner properties of the dynamic content.

I found a solution that work thou. IStringFragment implements IReferenceMap so its possible to return the Guid of the form that are used. You then have to check if that Guid is a xform Guid and then return the PlugInDescriptior[]


2) Make the forms selectable

After I manage to get the tab to be shown the next problem was to get the drop down on that tab to include the forms that currently is used on the page.

The dropdown (after a look with reflector) is populated by looping thru all the properties on the page and finding all the xform properties there.

My solution was to in the ICustomPlugInLoader  to add dynamic (if the page was not read only) xform property with the different xform Guids. That worked as a charm until I tried to retrieve some data. Strangely there was no result.

When I try to retrieve the post from a page with a xform property and look at all the pages I find the posts I'm trying to retrieve.

3) trying to get some data

After a bit more looking around there seems that the XFormPostings user control use XFormStatistics as a data source. That class uses the current selected property name and does another GetPage with the current pageLink to retrieve the Guid of the xform.


That's means that there are not a quick fix for this. You have to make your own User Control that replace the XFormPostings. :(

Do any of you have another idea?

Nov 03, 2008


Sangeeta Deshpande
Sangeeta Deshpande Sep 21, 2010 10:32 AM

How do I make xform selectable on the template by creating custom property for the template.

André Hedberg
André Hedberg Oct 19, 2011 12:41 PM

I was in the same exact situation. What you can do as a quick (a bit dirty too ;)) fix is too create a new page (e.g. XForm Statistics Page) type with just a XForm-property (or such). From this page, the editors selects the form of which statistics they want to view. They can then view the statistics just like before. I know... It's not the most beautiful solution, but it works. :) Hope this was to some help!

Please login to comment.
Latest blogs
Optimizely SendGrid SMTP host is deprecated

SendGrid is a services for sending email that is included in Optimizely DXP. Previously was the recommended SMTP server to use,...

Tomas Hensrud Gulla | Dec 4, 2022 | Syndicated blog

Hosting Optimizely CMS 12 on Docker Engine

Since Optimizely CMS can now be deployed as a Docker container, here is a demonstration of building, running and scaling an Optimizely CMS 12 site ...

Stefan Holm Olsen | Dec 4, 2022 | Syndicated blog

How to use CacheTagHelper with content areas in Optimizely CMS 12

I might be going out on a limb here - if you have a better solution, feel very free to share it!  Upgrading your Optimizely web application from .N...

Andreas J | Dec 2, 2022

The 1001st Piece in your 1000 Piece Puzzle: .NET Default Interface Functions

I was recently working with a client who wanted a reasonably large subsystem added to Optimizely that would add automated management to their...

Greg J | Nov 28, 2022 | Syndicated blog