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.Samples05.06. [FieldDefinitionElement(typeof(GenericCustomFieldEditorDefinitionElement))]07. public class CompositeFieldControlCustom : 08. CompositeFieldControl09. 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