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/
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
});
}
}
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?
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!
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?
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?
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.
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/
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.
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.
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
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;
}
}
}
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:
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?
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.
Can I download it somewhere and just browse the files or do I need to download and install it?
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.
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.
Did you change UI hint to "test" in both places - in ContactPageSelector and in page type property definition?
What do you mean? Page type property definition? Is this another new step?
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?
When I check under "edit custom property types" this newly added property I thought would be called "Test" is not showing.
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;}
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?
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.
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?
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.
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;
}
}
}
}