Anders Hattestad
Nov 3, 2008
  7823
(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;
   8:   
   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:          }
  39:   
  40:   
  41:          public string Render(EPiServer.PageBase hostPage)
  42:          {
  43:              throw new NotImplementedException();
  44:          }
  45:   
  46:          public string StateAsID
  47:          {
  48:              get
  49:              {
  50:                  if (_state != null)
  51:                      return "state" + Math.Abs(_state.GetHashCode());
  52:                  return "statenull";
  53:              }
  54:          }
  55:   
  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));
  65:   
  66:              }
  67:              set
  68:              {
  69:                  if (value != null)
  70:                  {
  71:                      _state = value;
  72:                      byte[] toDecodeByte = Convert.FromBase64String(value);
  73:   
  74:                      System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
  75:                      System.Text.Decoder utf8Decode = encoder.GetDecoder();
  76:   
  77:                      int charCount = utf8Decode.GetCharCount(toDecodeByte, 0, toDecodeByte.Length);
  78:   
  79:                      char[] decodedChar = new char[charCount];
  80:                      utf8Decode.GetChars(toDecodeByte, 0, toDecodeByte.Length, decodedChar, 0);
  81:                      string result = new String(decodedChar);
  82:                      Value = result;
  83:   
  84:                  }
  85:              }
  86:          }
  87:          #endregion
  88:   
  89:          #endregion
  90:   
  91:          #region IReferenceMap Members
  92:   
  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:          }
 103:   
 104:          void IReferenceMap.RemapPermanentLinkReferences(IDictionary<Guid, Guid> idMap)
 105:          {
 106:              base.RemapPermanentLinkReferences(idMap);
 107:          }
 108:   
 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.

Conclusion

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

Comments

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
Opti ID overview

Opti ID allows you to log in once and switch between Optimizely products using Okta, Entra ID, or a local account. You can also manage all your use...

K Khan | Jul 26, 2024

Getting Started with Optimizely SaaS using Next.js Starter App - Extend a component - Part 3

This is the final part of our Optimizely SaaS CMS proof-of-concept (POC) blog series. In this post, we'll dive into extending a component within th...

Raghavendra Murthy | Jul 23, 2024 | Syndicated blog

Optimizely Graph – Faceting with Geta Categories

Overview As Optimizely Graph (and Content Cloud SaaS) makes its global debut, it is known that there are going to be some bugs and quirks. One of t...

Eric Markson | Jul 22, 2024 | Syndicated blog

Integration Bynder (DAM) with Optimizely

Bynder is a comprehensive digital asset management (DAM) platform that enables businesses to efficiently manage, store, organize, and share their...

Sanjay Kumar | Jul 22, 2024

Frontend Hosting for SaaS CMS Solutions

Introduction Now that CMS SaaS Core has gone into general availability, it is a good time to start discussing where to host the head. SaaS Core is...

Minesh Shah (Netcel) | Jul 20, 2024

Optimizely London Dev Meetup 11th July 2024

On 11th July 2024 in London Niteco and Netcel along with Optimizely ran the London Developer meetup. There was an great agenda of talks that we put...

Scott Reed | Jul 19, 2024