20100317

EpiServer - Itera.MultiProperty examples

MultiProperty by Itera is very useful EpiServer extension.

Two basic ways of using MultiProperty are described on a blog by Anders Hattestad.

Basics

Most common way to use MultiProperty is to create set of fields and then create second property that allows user to create list of those items.

Let's assume user needs to provide list of ExampleItem.

public class ExampleItem
    {
        public string Field { get; set; }
        public string Regex { get; set; }        
        public string Default { get; set; }
    }

First you have to create property that lets user enter single item.

public class PropertyExampleField : PropertySingleBase
    {
        protected const string PROPERTY_NAME_FIELD = "Field";
        protected const string PROPERTY_NAME_REGEX = "Regex";
        protected const string PROPERTY_NAME_DEFAULT = "Default";

        PropertyDataCollection _innerPropertyCollection;
        protected override PropertyDataCollection InnerPropertyCollection
        {
            get
            {
                if (_innerPropertyCollection == null)
                {
                     _innerPropertyCollection =
                        new PropertyDataCollection
                            {
                                {PROPERTY_NAME_FIELD, new PropertyString()},
                                {PROPERTY_NAME_REGEX, new PropertyString()},
                                {PROPERTY_NAME_DEFAULT, new PropertyString()},
                            };
                }
                return _innerPropertyCollection;
            }
            set { _innerPropertyCollection = value; }
        }

        public string Field
        {
            get { return (PropertyCollection[PROPERTY_NAME_FIELD].Value as string) ?? ""; }
            set { PropertyCollection[PROPERTY_NAME_FIELD].Value = value; }
        }

        public string Regex
        {
            get { return PropertyCollection[PROPERTY_NAME_REGEX].Value as string; }
            set { PropertyCollection[PROPERTY_NAME_REGEX].Value = value; }
        }    

        public string Default
        {
            get { return PropertyCollection[PROPERTY_NAME_DEFAULT].Value as string; }
            set { PropertyCollection[PROPERTY_NAME_DEFAULT].Value = value; }
        }

        public ExampleItem ExampleItem
        {
            get
            {
                return new ExampleItem
                           {
                               Field = Field,
                               Regex = Regex,
                               Default = Default
                           };
            }
        }
    }

Then you have to create property that lets user create list of items.

[Serializable]
    [PageDefinitionTypePlugIn(DisplayName = "List of ExampleField")]
    public class ExampleFieldList : PropertyMultiBase
    {
        PropertyDataCollection baseProperties;
        public override PropertyDataCollection BaseProperties
        {
            get
            {
                if (baseProperties == null)
                {
                    baseProperties = new PropertyDataCollection { { "ExampleField", new PropertyExampleField() } };
                }
                return baseProperties;
            }
        }

        public List ExampleItems
        {
            get
            {
                List result = new List();
                foreach (PropertyExampleField item in PropertyCollection)
                {
                    result.Add(item.ExampleItem);
                }
                return result;
            }
        }

    }

Advanced

You can sort fields on save - it will help users to deal with long lists. You can remove empty fields - but you have to remember to let user have one empty so he can add new items. To achieve it override SerializeToXmlNode method in ExampleFieldList class.

public override System.Xml.XmlNode SerializeToXmlNode(PropertyDataCollection propCollection, PropertyDataCollection basePropertys, Dictionary newGuids)
        {
            List fields = new List();
            bool firstEmpty = true;
            foreach (PropertyData data in propCollection)
            {
                PropertyExampleField field = data as PropertyExampleField;
                if (field == null)
                {
                    continue;
                }
                if (field.Field != "")
                {
                    fields.Add(field);
                }
                else
                {
                    if (firstEmpty)
                    {
                        fields.Add(field);
                        firstEmpty = false;
                    }
                }
            }
            fields.Sort((a, b) => a.Field.CompareTo(b.Field));
            PropertyDataCollection newPropCollection = new PropertyDataCollection();
            foreach (PropertyExampleField data in fields)
            {
                newPropCollection.Add(data);
            }
            return base.SerializeToXmlNode(newPropCollection, basePropertys, newGuids);
        }

You an also force some mandatory items to be placed on the list each time user enters edit mode. To achieve it override ParseToSelf method in ExampleFieldList class.

Example below adds 3 fields named aaa, bbb and ccc.
Even if user removes any of them they will be recreated next time anyone enters edit mode.

public override void ParseToSelf(string xml, PropertyDataCollection propCollection, PropertyDataCollection basePropertys)
        {
            base.ParseToSelf(xml, propCollection, basePropertys);            
            string fieldList = "aaa,bbb,ccc";
            foreach (string part in fieldList.Split(",".ToCharArray()))
            {
                string fieldName = part.Trim();
                if (fieldName == "")
                {
                    continue;
                }
                bool found = false;
                foreach (PropertyData data in propCollection)
                {
                    PropertyExampleField field = data as PropertyExampleField;
                    if (field == null)
                    {
                        continue;
                    }
                    if (field.ExampleItem.Field == fieldName)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    propCollection.Add(
                        new PropertyExampleField 
                                           {
                                               Name = String.Format("ExampleField_{0}", Guid.NewGuid()),
                                               Field = fieldName,
                                               Regex = "",
                                               Default = ""
                                           });
                }
            }
        }

1 comment:

Atul Sirpal said...

Nice article

Could we implement uniqueness like data entered by user should be unique in multiproperty.Any idea regarding this.