November Happy Hour will be moved to Thursday December 5th.

Implementing CreateWritableClone() for a custom property

Vote:
 

Hi.

 

I am currently creating a custom property which will hold a list of banners. The banners are an imagevault media instance and a link which corresponds. I am following the tutorial made by Joel Abrahamsson, http://joelabrahamsson.com/creating-a-custom-episerver-property-with-a-custom-class-as-value/ even though it is a bit old I think I have managed to get everything right. The problem I am facing is when implementing IReadOnly's (EPiServer.Data.Entity) method CreateWritableClone(). The error message says that the return type should be of 'object' and when I change to object it says the return type should be 'BannerList'. I have supplied my custom class BannerList.cs below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using EPiServer.Data.Entity;

namespace EPiServer.Templates.InGellivare.BIT
{
    public  class BannerList : IEnumerable<Banner>, IReadOnly<BannerList>
    {
        private List<Banner> values;
        private bool isReadOnly;
        private bool isModified;

        #region Collection related

        public BannerList()
        {
            values = new List<Banner>();
        }

        public IEnumerator<Banner> GetEnumerator()
        {
            return (IEnumerator<Banner>)values.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Add(Banner banner)
        {
            ThrowIfReadOnly();

            isModified = true;

            values.Add(banner);
        }

        #endregion

        #region Object related (Create, Copy, Comparison et cetera)

        public BannerList CreateWritableClone()
        {
            var copy = new BannerList();
            copy.values = new List<Banner>(values);
            copy.isReadOnly = false;

            return (BannerList)copy;
        }

        public BannerList Copy()
        {
            var copy = (BannerList)MemberwiseClone();

            copy.values = new List<Banner>(values);

            return copy;
        }

        public override bool Equals(object obj)
        {
            var compareTo = obj as BannerList;

            if (compareTo == null)
            {
                return false;
            }

            return values.SequenceEqual(compareTo.values);
        }

        public override string ToString()
        {
            return JsonHelper.JsonSerializer<List<Banner>>(values);
        }

        public static BannerList Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentException("Cannot parse Bannerlist objects from null", "value");
            }

            var result = new BannerList();
            var banners = JsonHelper.JsonDeserialize<List<Banner>>(value);
            result.values.AddRange(banners);
            return result;
        }

        #endregion

        #region Version & Access control

        public void MakeReadOnly()
        {
            isReadOnly = true;
        }

        public bool IsReadOnly
        {
            get { return isReadOnly; }
        }

        private void ThrowIfReadOnly()
        {
            if (IsReadOnly)
            {
                throw new NotSupportedException("The list of banners is read-only.");
            }
        }

        public bool IsModified
        {
            get
            {
                return isModified;
            }
            set
            {
                ThrowIfReadOnly();
                isModified = value;
            }
        }

        #endregion
    }
}

    

And the error message reads as following:

Error 1 'EPiServer.Templates.InGellivare.BIT.BannerList' does not implement interface member 'EPiServer.Data.Entity.IReadOnly.CreateWritableClone()'. 'EPiServer.Templates.InGellivare.BIT.BannerList.CreateWritableClone()' cannot implement 'EPiServer.Data.Entity.IReadOnly.CreateWritableClone()' because it does not have the matching return type of 'object'. C:\EPiServer\Sites\GVE\Templates\InGellivare\BIT\BannerList.cs 10 19 nyaGellivare

Thanks in advance,

David Rutqvist

#74055
Aug 20, 2013 8:32
Vote:
 

The generic IReadOnly<T> inherits IReadOnly meaning you should have two implementations of CreateWritableClone, one typed and one returning object. This can be done with an explicit interface implementatation. An example could be like below which implements IReadOnly<PropertyData>:


object IReadOnly.CreateWritableClone()
{
    //Call via generic interface
    return this.CreateWritableClone();
}


public virtual PropertyData CreateWritableClone()
{
    PropertyData prop = (PropertyData)this.MemberwiseClone();
    prop.Parent = null;
    prop._isReadOnly = false;
    return prop;
}

#74057
Aug 20, 2013 10:13
Vote:
 

Thanks a lot. Could not find any reference to that. Is this new for EPi7?

#74058
Aug 20, 2013 10:19
Vote:
 

No, it is not new for CMS7. But since the implementation of the nongeneric is in Base class PropertyData a custom property implementation typically does not have to bother about the non-generic variant (returning object) they just override the variant returning PropertyData.

I can also see that you do not inherit PropertyData (or some other subclass to it), that is a requirement for a custom property.

#74061
Aug 20, 2013 11:02
Vote:
 

I have another class which inherits PropertyData and holds a BannerList object as the value (as in the tutorial).

#74062
Aug 20, 2013 11:05
Vote:
 

Ok, I'll see. That's according to best practice! ;-)

#74063
Aug 20, 2013 11:09
Vote:
 

Now when looking more in history I see that the method CreateWritableClone actually was added to IReadOnly in CMS7. Prior to that the non-generic interface was quite odd and difficult to work with since it lacked that method...

#74064
Aug 20, 2013 11:32
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.