EPiServer DDS + Enum
We found a problem when having Nullable Enum values in our DDS objects. We got an error “Invalid cast from ‘System.Int32′ to ‘RoleData.MyEnum’.” when we tried to iterate through our repository.
Others seem to have the same problem as well.
According to Paul Smith there seems to be some problems, I didn’t get the e-mail response myself so I must get back with more details.
This is my solution, using a TypeHandler, had totally forgotten about that part in the DDS Example Package.
public class EnumTypeHandler : ITypeHandler
{
//From int to enum
public object FromDatabaseFormat(string propertyName, object propertyValue, Type targetType, Type ownerType)
{
if (propertyValue == null)
return null;
Type valueType = targetType;
if (IsNullable(targetType))
{
valueType = Nullable.GetUnderlyingType(targetType);
}
if (valueType.IsEnum)
{
string stringValue = Convert.ToString(propertyValue);
return Enum.Parse(valueType, propertyValue.ToString());
}
return propertyValue;
}
//returns int type
public Type MapToDatabaseType(Type type)
{
if (type.IsEnum)
{
if(IsNullable(type))
return typeof(int?);
return typeof(int);
}
return type;
}
//convert enum to int
public object ToDatabaseFormat(string propertyName, object propertyValue, Type ownerType)
{
if (propertyValue == null)
return null;
if (propertyValue is Enum)
return Convert.ToInt32(propertyValue);
return propertyValue;
}
private bool IsNullable(Type type)
{
return (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
}
}
It only takes care of int Enums at the moment but it’ll do.
And in EPiServer FirstBeginRequest I added the Handler by adding:
if (!GlobalTypeHandlers.Instance.ContainsKey(enumType))
GlobalTypeHandlers.Instance.Add(enumType, new EnumTypeHandler());
Where enumType is each Enum I need to handle in my DDS object.
I’m creating a “widget” where the client is supposed to be able to change color to a Teaser. The color options should be editable quite easily.
The widget is added to the page by using Dynamic Content.
So I’m using the PropertyDropDownList added in EPiServer CMS 6 R2 so an administrator can edit the options through the Administrator Mode (or when PagetTypeBuilder 2 comes, a developer by creating a class deriving from IUpdateGlobalPropertySettings<MultipleOptionsListSettings>).
But since all ways to change the Property’s Settings values are locked from external binaries, I couldn’t find any other way to connect my Global Setting to the DropDownList in my Dynamic Content except creating a Custom Property that derives from PropertyDropDownList.
After that I create a Global Setting for DropDownList with some colors which I set as default for my PropertyTeaserColorDropDownList.
So by adding a Property of type PropertyTeaserColorDropDownList in my Dynamic Content class, I can let my Editor select a color from a list managed by the Administrator.
Code examples
public class PropertyTeaserColorDropDownList : PropertyDropDownList
{
}
[DynamicContentPlugIn(DisplayName = "Front Teaser", ViewUrl = "~/Widgets/FrontTeaserWidget/FrontTeaserWidget.ascx")]
public partial class FrontTeaserWidgetControl : WidgetControlBase
{
public PropertyTeaserColorDropDownList TeaserColor { get; set; }
}
It feels a bit cumbersome to create a Custom Property for this. It would be nice if I could set the SettingsId somehow or if it could be set by some attribute.
Summary of resize image in EPiServer Template Foundation
I’m working on my first ETF project, and sadly I’m not that overwhelmed but that’s another story.
This story is about using the resize image function, I didn’t find a good blog post on how to use this, except how to activate the functionality:
I didn’t setup this project but as you can read on Ted’s blog about Creating a new website using Template Foundation you’re supposed to add the following to web.config:
<configuration>
<configSections>
<section name=”DynamicImageProcessor” type=”TemplateFoundation.Handlers.DynamicImageProcessor.ProcessorConfig” />
</configSections>
<DynamicImageProcessor>
<Cache CacheDirectory=”C:\Temp\dynamicimageprocessor-test” Enabled=”true” />
</DynamicImageProcessor>
</configuration>
You’re also supposed to add these handlers on the paths you want to activate:
<add name=”png” verb=”GET,HEAD” path=”*.png” type=”TemplateFoundation.Handlers.DynamicImageProcessor.Processor” />
<add name=”jpg” verb=”GET,HEAD” path=”*.jpg” type=”TemplateFoundation.Handlers.DynamicImageProcessor.Processor” />
<add name=”gif” verb=”GET,HEAD” path=”*.gif” type=”TemplateFoundation.Handlers.DynamicImageProcessor.Processor” />
In my example I want to be able to modify images uploaded to the PageFiles directory, Therefore my configuration will look like this;
<location path=”PageFiles”>
<system.webServer>
<handlers>
<add name=”webresources” path=”WebResource.axd” verb=”GET” type=”System.Web.Handlers.AssemblyResourceLoader” />
<!– Dynamic Image Processor –>
<add name=”png” verb=”GET,HEAD” path=”*.png” type=”TemplateFoundation.Handlers.DynamicImageProcessor.Processor” />
<add name=”jpg” verb=”GET,HEAD” path=”*.jpg” type=”TemplateFoundation.Handlers.DynamicImageProcessor.Processor” />
<add name=”gif” verb=”GET,HEAD” path=”*.gif” type=”TemplateFoundation.Handlers.DynamicImageProcessor.Processor” />
<!– End of Dynamic Image Processor–>
<add name=”wildcard” path=”*” verb=”*” type=”EPiServer.Web.StaticFileHandler, EPiServer” />
</handlers>
</system.webServer>
<staticFile expirationTime=”-1.0:0:0″ />
</location>
I know that already, how do I use this?
To fetch a resized image, all I need to do is to browse to the file and add some parameters:
http://myproject/PageFiles/4474/328.jpg?w=107&ch=76
This combination of w and ch means that the size will be shrunk to 107 px width, but cropped to 76 px height.
Other parameters you can add are:
integers:
w: resized width, the image will be resized to fit this width (can be replaced with “width”)
h: resized height, the image will be resized to fit this height (can be replaced with “height”)
cw: cropped width, the image will be cropped to fit this width
ch: cropped height, the image will be cropped to fit this height
ox: offset x position on cropping, default is center of image
oy: offset y position on cropping, default is center of image
booleans:
r: keep aspect ratio
up: the image may be resized to larger than original image
I hope this post gave you some help on how to change the sizes in a Template Foundation web site.
/Alf
:<section name="DynamicImageProcessor" type="TemplateFoundation.Handlers.DynamicImageProcessor.ProcessorConfig" /
Hello world!
Well here I go again, I think this is the third time I try bloggin.
I’m quite interested in routines and structures so I’ll try focus on that.
At least I’ll write about web development, programming, design etc.
Other things in my TODO is:
- Writing the “about me”.
- Finish the alfnilsson.se domain.
- Making my own template for WordPress, I’ve done it before so it shouldn’t be that hard!
- Complain about things that doesn’t seem to work
There, done for now.
Bye
</Alf>
Multiproperty from behind
Okay this is my first tech-blog so bare with me. Please send comments if some things I write are not properly explained.
Starting
A colleague of mine had a problem with a list of pages using Itera.MultiProperty.
He had started to make two CustomProperties as explained in the examples in the Itera.MultiProperty.Examples namespace in Itera.MultiProperty.dll:
PropertyLegacyLinks inheriting from PropertyMulitBase
[EPiServer.PlugIn.PageDefinitionTypePlugIn(DisplayName = "Legacy links", Description = "List of legacy links")]
public class PropertyLegacyLinks : PropertyMulitBase
{
PropertyDataCollection _innerPropertyCollection;
object lockObject = new object();
public override PropertyDataCollection BasePropertys
{
get
{
if (_innerPropertyCollection == null)
{
lock (lockObject)
{
PropertyDataCollection _new = new PropertyDataCollection();
_new.Add(Translate("/legacylinksproperty/legacylink"), new PropertyLegacyLink());
_innerPropertyCollection = _new;
}
}
return _innerPropertyCollection;
}
}
}
PropertyLegacyLink inheriting from PropertySingleBase
public class PropertyLegacyLink : PropertySingleBase
{
PropertyDataCollection _innerPropertyCollection;
object lockObject = new object();
protected override PropertyDataCollection InnerPropertyCollection
{
get
{
if (_innerPropertyCollection == null)
{
lock (lockObject)
{
PropertyDataCollection _new = new PropertyDataCollection();
_new.Add(Translate("/legacylinksproperty/formerlink"), new PropertyString(""));
_new.Add(Translate("/legacylinksproperty/currentlink"), new PropertyPageReference());
_innerPropertyCollection = _new;
}
}
return _innerPropertyCollection;
}
set
{
lock (lockObject)
{
_innerPropertyCollection = value;
}
}
}
}
PropertyLegacyLink contained a String (<= 255) and a PageReference which should be listed on the page.
Frontend
He had made it work and render according to Anders Hattestad’s blog post <EPiServer:Property on steroids /> where he used the <Itera:Property> iterating through the PropertyLegacyLinks Property here called “Legacy”,
Inside the Itera:Property there was another Itera:Property iterating the PropertyLegacyLink printing its values.
<Itera:Property ID="PropertyCtrl" runat="server" SuppressEmpty="false" PropertyName="Legacy">
<ItemTemplate>
<Itera:Property PropertyName="this.PropertyCollection" SuppressEmpty="true" runat="server" EnableViewState="false">
<HeaderTemplate>
<table border="1">
<tr>
<th colspan="2">
Legacy Link
</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
{this.Name}
</td>
<td>
{this.Value}
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</Itera:Property>
</ItemTemplate>
</Itera:Property>
Rendering
| Legacy Link | |
|---|---|
| LegacyLink_d43da6749d2247fe9d038c69ae4be1ff | Tidigare länk
16 |
| LegacyLink_0c6a5fc3e2344c74a452e63ea20c833b | Äldre länk
15 |
Very nice if you want to see what your MultiProperty contains and you can probably work some more with the Itera:MultiProperty to make it look good. But what if we want to fetch the data from Backend?
Backend
After some digging in Red Gate’s Reflector I found out that the MultiProperty is a PropertyDataCollection containing rows with PropertyDataCollection containing the Properties.
What we need to do is iterate through the first PropertyDataCollection by using
PropertyLegacyLinks legacies = (PropertyLegacyLinks)CurrentPage.Property["Legacy"];
PropertyDataCollection legacyLinksCollection = legacies.PropertyCollection;
PropertyDataCollection legacyLinkCollection;
foreach (PropertyLegacyLink item in legacyLinksCollection)
{
legacyLinkCollection = item.PropertyCollection;
}
Where you can get your string through (string)legacyLinkCollection[0].Value and (PageReference)legacyLinkCollection[1].Value.
Polishing
Using PropertyDataCollections needs alot of casting. So what I would suggest is giving the PropertyLegacyLinks a List<PropertyLegacyLink> as a Property and giving PropertyLegacyLink a string and a PageReference Property, such as this:
[EPiServer.PlugIn.PageDefinitionTypePlugIn(DisplayName = "Legacy links", Description = "List of legacy links")]
public class PropertyLegacyLinks : PropertyMulitBase
{
PropertyDataCollection _innerPropertyCollection;
object lockObject = new object();
private List<PropertyLegacyLink> _legacyLinks;
public List<PropertyLegacyLink> LegacyLinks
{
get
{
if (_legacyLinks == null)
{
_legacyLinks = new List<PropertyLegacyLink>();
for (int i = 0; i < BasePropertys.Count; i++)
{
PropertyLegacyLink item = BasePropertys[i] as PropertyLegacyLink;
_legacyLinks.Add(item);
}
}
}
return _legacyLinks;
}
}
public override PropertyDataCollection BasePropertys
{
get
{
if (_innerPropertyCollection == null)
{
lock (lockObject)
{
PropertyDataCollection _new = new PropertyDataCollection();
_new.Add(Translate("/legacylinksproperty/legacylink"), new PropertyLegacyLink());
_innerPropertyCollection = _new;
}
}
return _innerPropertyCollection;
}
}
}
and
public class PropertyLegacyLink : PropertySingleBase
{
PropertyDataCollection _innerPropertyCollection;
object lockObject = new object();
private string _formerlink;
public string FormerLink
{
get
{
if (_formerlink == null)
{
_formerlink = this.PropertyCollection[0].Value as string ?? string.Empty;
}
return _formerlink;
}
set
{
_formerlink = value;
}
}
private PageReference _currentLink;
public PageReference CurrentLink
{
get
{
if (_currentLink == null)
{
_currentLink = this.PropertyCollection[1].Value as PageReference ?? PageReference.EmptyReference;
}
return _currentLink;
}
set
{
_currentLink = value;
}
}
protected override PropertyDataCollection InnerPropertyCollection
{
get
{
if (_innerPropertyCollection == null)
{
lock (lockObject)
{
PropertyDataCollection _new = new PropertyDataCollection();
_new.Add(Translate("/legacylinksproperty/formerlink"), new PropertyString(""));
_new.Add(Translate("/legacylinksproperty/currentlink"), new PropertyPageReference());
_innerPropertyCollection = _new;
}
}
return _innerPropertyCollection;
}
set
{
lock (lockObject)
{
_innerPropertyCollection = value;
}
}
}
}
