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

Problems with custom DropDownList property

Vote:
 

Hi,

I'm trying to implement a drop down custom property containing locations. It works great in our v6 but when I try to add it to our new v7 proejct it shows up as a textbox. Any idea why? Here's the code of the two classes.

namespace BM_EPi.Models.Properties

{

    [Serializable]

    [PropertyDefinitionTypePlugIn]

    public class Location : EPiServer.Core.PropertyString

    {

        public override EPiServer.Core.IPropertyControl CreatePropertyControl()

        {

            return new LocationControl();

        }

 

    }

}

 
 

namespace BM_EPi.Models.Properties

{

    publicclassLocationControl : EPiServer.Web.PropertyControls.PropertyTextBoxControlBase

    {

        public override bool SupportsOnPageEdit

        {

            get

            {

                return false;

            }

        }

 

        protected System.Web.UI.WebControls.DropDownList ddl;

 

        public override void CreateEditControls()

        {

            ddl = new System.Web.UI.WebControls.DropDownList();

           

            ddl.Items.Add(new ListItem("1", "1"));

            ddl.Items.Add(new ListItem("2", "2"));

            ddl.Items.Add(new ListItem("3", "3"));

 

            this.ApplyControlAttributes(ddl);

            Controls.Add(ddl);

        }

 

        public override void ApplyEditChanges()

        {

            if (ddl.SelectedValue != null) SetValue(ddl.SelectedValue);

            else SetValue(null);

        }

 

        public Location Location

        {

            get

            {

                return PropertyData as Location;

            }

        }

    }

}

 
#81378
Feb 16, 2014 20:57
Vote:
 

I would suggest that you create an editor descriptor instead.

See Linus Ekströms blog post for inspiration: http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2012/9/EPiServer-7-Configuring-editors-for-your-properties/

#81379
Edited, Feb 16, 2014 21:20
Vote:
 

Property definition:

[Display(GroupName = SystemTabNames.Content, Order = 15)]
[CultureSpecific]
[BackingType(typeof(PropertyNumber))]
[EditorDescriptor(EditorDescriptorType = typeof(EnumEditorDescriptor<HeaderType>))]
public virtual HeaderType HeaderLevel { get; set; }

    

HeaderLevel is just ordinary enum:

public enum HeaderType
{
    None,
    H1,
    H2,
    ...
}

    

Enumeration descriptor:

public class EnumEditorDescriptor<TEnum> : EditorDescriptor where TEnum : struct, IComparable, IConvertible, IFormattable
{
    public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
    {
        SelectionFactoryType = typeof(EnumSelectionFactory<TEnum>);
        ClientEditingClass = "epi-cms/contentediting/editors/SelectionEditor";
        base.ModifyMetadata(metadata, attributes);
    }
}

    

Factory itself (with some localization stuff inside - optional):

public class EnumSelectionFactory<TEnum> : ISelectionFactory
{
    public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
    {
        var values = Enum.GetValues(typeof(TEnum));
        return (from object value in values
                select new SelectItem
                {
                           Text = EnumExtensions.GetLocalizedEnumValue(value),
                           Value = value
                 });
    }
}

    

#81380
Feb 16, 2014 21:42
Vote:
 

Sorry for the late reply. It's a busy schedule at the moment.

And excuse me once more but I don't get what this is about and what I'm suppose to do with it... :/ Any more pointers to give?

#81532
Feb 18, 2014 20:36
Vote:
 

Just add EnumEditorDescriptor<TEnum> and EnumSelectionFactory<TEnum> classes to your model lirbary if any or to your web project. Just take care of what will be the Text property of newly created SelectItem (in sample above - it used our own location method to get display text of the item based on enum type).

Then add enum that will contain all values from this code fragment:

ddl.Items.Add(new ListItem("1", "1"));
ddl.Items.Add(new ListItem("2", "2"));
ddl.Items.Add(new ListItem("3", "3"));

    

Let's say LocationEnum:

public enum LocationEnum
{
    None,
    One,
    Two,
    Three
}

    

Then set this LocationEnum as property of page type:

public class MyPageType : YourBasePageDataClass
{
    [Display(GroupName = SystemTabNames.Content, Order = 15)]
    [CultureSpecific]
    [BackingType(typeof(PropertyNumber))]
    [EditorDescriptor(EditorDescriptorType = typeof(EnumEditorDescriptor<LocationEnum>))]
    public virtual LocationEnum Location { get; set; }
}

    

After this you should be able to see dropdown while editing the page and should get LocationEnum value while working with page data instance.

 

Hope this helps!

#81533
Feb 18, 2014 20:44
Vote:
 

Suppose I'm a real pain in the *ss here but I can't get this to work. Would you mind "doing the job for me" and add it to my class I pasted above? Or is it for the Location.cs?

#81623
Feb 20, 2014 20:15
Vote:
 

Property definition has to be added to your page type.

public class MyPage : PageData
{
    // ...

    [Display(GroupName = SystemTabNames.Content, Order = 15)]
    [CultureSpecific]
    [BackingType(typeof(PropertyNumber))]
    [EditorDescriptor(EditorDescriptorType = typeof(EnumEditorDescriptor<LocationEnum>))]
    public virtual LocationEnum Location { get; set; }
}

    

If you have Enum descriptor available and added page property of type System.Enum - EPiServer should treat it as drop down box in UI editor.

Do you receive any errors? How field is redered to UI?

#81652
Feb 22, 2014 12:23
Vote:
 

Hmm So I'm suppose to add this to my PAGE TYPE file? This is only used in edit mode, does that make a difference?

I've tried adding it to my pagetype and I can't find a namespace for EditorDescriptor as well as I don't what LocationEnum is suppose to be. Feels like I'm in way over my head here.

#81653
Feb 22, 2014 20:35
Vote:
 

I've also tried pasting this code used in the example below but it fails because I there's no EPiserver.Shell to be reference... :/

http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2012/9/EPiServer-7-Configuring-editors-for-your-properties/

#81654
Feb 22, 2014 20:58
Vote:
 

The EditorDescriptor class can be found in the EPiServer.Shell.ObjectEditing.EditorDescriptors namespace in the EPiServer.Shell.dll.

You should find EPiServer.Shell.dll among your other EPiServer dll files. If you're using Nuget it is available in the EPiServer.Framework.dll.

You add the [EditorDescriptor(...)] part to the Property in your PageType. This is to connect the Property to the Dropdown list control in edit mode.

Valdis Enum property EditorDescriptor might be a bit too advanced for you to grasp the concept of EditorDescriptors.

Start with looking at Linus Ekströms blog post or look at the Business/EditorDescriptors/ContactPageSelector example in Alloy templates.

To summarize the concept with a dropdown EditorDescriptor in EPiServer 7:

1: You need a class inheriting EditorDescriptor.
2: In the ModifyMetadata method you specify that ClientEditingClass = "epi-cms/contentediting/editors/SelectionEditor" and sets a SelectionFactory.
3: The SelectionFactory is the class that has the list of options for your dropdownlist.
4: All you need to do in your SelectionFactory is to create a list of SelectItem. Here is one example taken from Linus Ekström:

var languages = new List<SelectItem>();
languages.Add(new SelectItem(){ Value = "EN", Text = "English"});
languages.Add(new SelectItem(){ Value = "SW", Text = "Swahili"});
languages.Add(new SelectItem(){ Value = "PF", Text = "French Polynesia"});
return languages;

5: To tell EPiServer that you want your EditorDescriptor on a specific Property, all you need to do is to add the EditorDescriptor attribute.
The example with UIHint use to work all fine, but I guess the [EditorDescriptor(EditorDescriptorType = typeof(YourEditorDescriptor)] might work better.

#81656
Feb 23, 2014 0:18
Vote:
 

Alf,

I'll try that out but before I begin; are you not suppose to create a new Custom Property like you used to? At all? I mean the way you did in v6 where you got the class and the added controller class.

#81717
Feb 24, 2014 20:02
Vote:
 

The old way with customproperties and their controls are a legacy way.

it's better to learn this new way and your example is very easy

#81718
Feb 24, 2014 20:05
Vote:
 

I guess I'm missing something. Or a whole lot. :) For instance, where do I name it? Where do I specify what property to store?

Here's what I have so far:

publicclassTestProperty : EditorDescriptor

    {

        public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)

        {

            ClientEditingClass = "epi-cms/contentediting/editors/SelectionEditor";

        }

 

        publicclassLanguageSelectionFactory : ISelectionFactory

        {

            public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)

            {

                var languages = new List<SelectItem>();

                

                languages.Add(new SelectItem(){ Value = "1", Text = "1"});

                languages.Add(new SelectItem(){ Value = "2", Text = "2"});

                languages.Add(new SelectItem(){ Value = "3", Text = "3"});

 

                return languages;

            }

        }

    }

 
#81719
Feb 24, 2014 20:29
Vote:
 

If you are basing the project on EPiServer 7.5, there is even an attribute that makes it possible to bypass the EditorDescriptor and just add the attribute and Selection Factory. Check my blog post for info about these attributes:

http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/12/SingleMultiple-selection-in-EPiServer-75/

#81720
Feb 24, 2014 20:36
Vote:
 

Sorry, not in 7.5 yet. Need to get it up and running in 7 first... :)

So what's next? Am I on the right track?

#81759
Feb 25, 2014 20:35
Vote:
 

Have a look at the ContactPageSelectionFactory class in the Alloy sample project and how it's used and you should be able to use that pattern.

#81763
Feb 26, 2014 7:24
Vote:
 

Can I download it somewhere and just browse the files or do I need to download and install it?

#81896
Feb 28, 2014 9:43
Vote:
 

Use the EPiServer Deployment Center.

Click the "Install site and SQL Server database" link for the EPiServer version you're working on.

Later in the steps you will see an option where you can install Alloy Templates. Select MVC or WebForms depending on which framework you're working with.

#81897
Feb 28, 2014 9:47
Vote:
 

So I installed the Alloy templates and imported the two files (ContactPageSelector.cs and ContactPageSelectionFactory.cs) into my existing project, swapped the GetSelections to a static 1,2,3 set of SelectItems and change the UIHint to "test". Then what? There is no new property in my site and I'm even more lost here.

#82006
Mar 03, 2014 20:53
Vote:
 

Did you change UI hint to "test" in both places - in ContactPageSelector and in page type property definition?

#82008
Mar 04, 2014 5:59
Vote:
 

What do you mean? Page type property definition? Is this another new step?

#82049
Mar 04, 2014 19:36
Vote:
 

All I've done is copied the two files mentioned above (ContactPageSelector.cs and ContactPageSelectionFactory.cs) to my project. What else do I need to do?

#82050
Mar 04, 2014 19:37
Vote:
 

When I check under "edit custom property types" this newly added property I thought would be called "Test" is not showing.

#82051
Mar 04, 2014 19:43
Vote:
 

When you say "no new property"? Are you looking in admin mode for a new Custom Property? In that case you're a bit off.

The EditorDescriptor does not create a new Custom Property. It only tells Edit Mode in EPiServer that this property should not be rendered as a normal text box.
The ClientEditingClass = ".....SelectionEditor" part tells EPiServer that this is supposed to be rendered as a dropdown in Edit Mode.

It is still stored as a string and is considered to be a normal string when it comes to the data.

When you say that you have changed the UIHint to "test", I guess that your ContactPageSelector class looks something like this?

[EditorDescriptorRegistration(TargetType = typeof(string), UIHint = Global.SiteUIHints.Contact)]
public class ContactPageSelector : EditorDescriptor

To connect your property to this new dropdown, you add the following in your page type class

[UIHint("test")]
public virtual string MyProperty {get;set;}

You may add the [Display(...)] part but that is not important to this example.

 

Edit:

In case of [UIHint("test")] you can also write

[EditorDescriptor(EditorDescriptorType = typeof(ContactPageSelector))]
public virtual string MyProperty {get;set;}

#82052
Edited, Mar 04, 2014 19:45
Vote:
 

First off, my ContactPageSelector looks like this:

[EditorDescriptorRegistration(TargetType = typeof(string), UIHint = "test")]

    publicclassContactPageSelector : EditorDescriptor
   {

        public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
       {

            SelectionFactoryType = typeof(ContactPageSelectionFactory);         

            ClientEditingClass = "epi.cms.contentediting.editors.SelectionEditor";  

            base.ModifyMetadata(metadata, attributes);
       }
  }

When I use the original UIHint = Global.SiteUIHints.Contact i says that EPiServer.Global doesn't contain a definition for SiteUIHints. What needs to be done there?

#82054
Mar 04, 2014 19:55
Vote:
 

Let's focus on getting the EditorDescriptor works, having constants such as Global.SiteUIHints.Contact is more like a nice way to make sure that you have written the same UIHint in the EditorDescriptor as well as on your Property.

#82056
Mar 04, 2014 19:57
Vote:
 

So I can set it to "test" instead?

#82057
Mar 04, 2014 19:58
Vote:
 

Yes

#82058
Mar 04, 2014 19:58
Vote:
 

Oh, NOW I get it! I didn't see the connection to the page type. I know, you've written it time after time but I'm not used to adding page properties that way.

THANK! YOU!

Where do I send the flowers?

#82059
Mar 04, 2014 20:03
Vote:
 

Nice that you got it working :)

I hope you get the knack on how you can add properties like this. In 7.5 they have simplified some common ways to create interfaces to editors such as dropdowns and things like that.

#82060
Mar 04, 2014 20:06
Vote:
 

I see. I just went with "the old" way.

Any idea why I got two page types with the same name when I added this property?

#82061
Mar 04, 2014 20:08
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* 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.