Using a Custom Interface Widget when creating a Custom Field
Now that dynamic fields (metafields) have been re-introduced in the Sitefinity 4 RC2 is there any guidance on how to create a custom user control for entering the data? That is, when creating a dynamic field you can choose "Custom..." for the interface widget and are then prompted for the path of the usercontrol. How exactly should a developer go about implementing this custom user control? What interfaces need to be implemented, or what classes within the Sitefinity framework need to be extended? An example would be great (even if it is a rudimentary one that shows how to do this in the most basic form).
I'm surprised no one has tried to do this before, so I'm going to bump this with more information.
What I'm doing is attempting alter the Blog Post entity to add a new custom field, and also specifying my own as the editor. Since there is no documentation or guidance on how to accomplish this I've been attempting to perform this through trial and error.
I've created a new class within my Sitefinity solution named 'GenericCustomFieldEditor' that is intended to be the definition of the editor to associated with my custom field. When choosing 'Custom...' and entering the fully-qualified namespace 'SitefinityWebApp.WebControls.GenericCustomFieldEditor' I initially received an error stating that it did not implement the Telerik.Sitefinity.Web.UI.Fields.Contracts.IField namespace. I resolved this by having my class extend from Telerik.Sitefinity.Web.UI.Fields.FieldControl, but not when I choose to save my new field from the Sitefinity administration interface I get the following error:
Index was outside the bounds of the array.
Which is rather meaningless. I assume this has to be a problem within the Sitefinity 4 codebase, as the SdrConfigExample.e2e log file reports the extended details as:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Telerik.Sitefinity.ModuleEditor.Web.Services.Model.DefinitionBuilder.TryGetDefinitionElementType(String fieldType, Type& fieldDefinitionType)
at Telerik.Sitefinity.ModuleEditor.Web.Services.Model.DefinitionBuilder.CreateDefinitionElement(String fieldType, Object definition, ConfigElement parent, Boolean resolveElementType)
at Telerik.Sitefinity.ModuleEditor.Web.Services.Model.CustomFieldsContext.CreateDynamicDefinitionElement(WcfCustomField field, ConfigElement parent)
at Telerik.Sitefinity.ModuleEditor.Web.Services.Model.CustomFieldsContext.SaveFieldDefinition(WcfCustomField field)
at Telerik.Sitefinity.ModuleEditor.Web.Services.Model.CustomFieldsContext.AddOrUpdateCustomFields(IDictionary`2 fields)
at Telerik.Sitefinity.ModuleEditor.Web.Services.ModuleEditorService.ApplyChangesInternal(ModuleEditorContext context, String providerName)
at SyncInvokeApplyChanges(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
"AddFields"
:
[
"Key"
:
"CustomField"
,
"Value"
:
"Name"
:
"CustomField"
,
"ContentType"
:
"Long text"
,
"FieldTypeKey"
:
"LongText"
,
"IsCustom"
:
true
,
"Definition"
:
"FieldName"
:
"CustomField"
,
"FieldType"
:
"SitefinityWebApp.WebControls.GenericCustomFieldEditor"
,
"FieldVirtualPath"
:
null
,
"Title"
:
"CustomField"
,
"Example"
:
""
,
"CssClass"
:
""
,
"DefaultValue"
:
""
,
"RenderChoiceAs"
:3,
"MutuallyExclusive"
:
true
,
"Choices"
:
""
,
"VisibleViews"
:[],
"Hidden"
:
false
,
"ValidatorDefinition"
:
"MinLength"
:
"0"
,
"TaxonomyId"
:
null
,
"DatabaseMapping"
:
"ClrType"
:
"System.String"
,
"DbType"
:
"CLOB"
,
"DbSqlType"
:
"TEXT"
,
"DbLength"
:
""
,
"DbPrecision"
:
""
,
"DbScale"
:
""
,
"Nullable"
:
true
,
"Indexed"
:
false
,
"ColumnName"
:
""
],
"ContentType"
:
"Telerik.Sitefinity.Blogs.Model.BlogPost"
,
"DefaultFields"
:[],
"RemoveFields"
:[]
Hello Bob,
Currently you can add only a custom control ( there are issues when you use a user control). You need to create a custom control that inherits from CompositeFieldControl or completely custom control that implements IField interface.
sample
using
System;
using
Telerik.Sitefinity.Web.UI.Fields;
namespace
Telerik.Sitefinity.Samples
class
CompositeFieldControlCustom : CompositeFieldControl
protected
override
System.Web.UI.WebControls.WebControl TitleControl
get
throw
new
NotImplementedException();
protected
override
System.Web.UI.WebControls.WebControl DescriptionControl
get
throw
new
NotImplementedException();
protected
override
System.Web.UI.WebControls.WebControl ExampleControl
get
throw
new
NotImplementedException();
protected
override
void
InitializeControls(Web.UI.GenericContainer container)
throw
new
NotImplementedException();
protected
override
string
LayoutTemplateName
get
throw
new
NotImplementedException();
Hi Ivan -- I tried your solution but still received an IndexOutOfRangeException.
I don't like to do this because Sitefinity 4 should be a working product, but I opened Reflector and dug through to find why this is occurring. There appears to be an error with the following static method declared in the Telerik.Sitefinity.ModuleEditor.Web.Services.Model.DefinitionBuilder class.
01.
private
static
bool
TryGetDefinitionElementType(
02.
string
fieldType,
03.
out
Type fieldDefinitionType)
04.
05.
fieldDefinitionType =
null
;
06.
Type elementType = TypeResolutionService.ResolveType(fieldType);
07.
if
(elementType.IsArray)
08.
09.
elementType = elementType.GetElementType();
10.
11.
FieldDefinitionElementAttribute attribute =
12.
elementType.GetCustomAttributes(
13.
typeof
(FieldDefinitionElementAttribute),
false
)[0]
14.
as
FieldDefinitionElementAttribute;
15.
if
(attribute !=
null
)
16.
17.
fieldDefinitionType = attribute.FieldDefinitionType;
18.
return
true
;
19.
20.
return
false
;
21.
01.
using
System;
02.
using
Telerik.Sitefinity.Web.UI.Fields;
03.
04.
namespace
Telerik.Sitefinity.Samples
05.
06.
[FieldDefinitionElement(
typeof
(GenericCustomFieldEditorDefinitionElement))]
07.
public
class
CompositeFieldControlCustom :
08.
CompositeFieldControl
09.
10.
...
11.
12.
Hello Bob Evans,
You are right, there should be a check if the GetCustomAttributes call returned an array with a length greater than zero before attempting to access any element with an index.
The fix will be available in next releases.
Thanks for your findings! I updated your Telerik points.
Kind regards,
Milena
the Telerik team