1-888-365-2779
+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / Custom Field Definition Element and Control

Custom Field Definition Element and Control

7 posts, 0 answered
  1. Bobby
    Bobby avatar
    56 posts
    Registered:
    11 Feb 2009
    17 Jan 2012
    Link to this post

    I am trying to implement a custom field control that is similar to the FieldImage control. However, I would like to bind to multiple images. I decided to create a custom control wrapping a FieldImage in a RadListView. I have already added a OneToMany relationship using the MetadataManager on my custom content to store the images. I am having trouble getting a handle to the DataItem that should be bound to my custom field control. Any help would be greatly appreciated. I have posted my code below:

    [FieldDefinitionElement(typeof(ImageListFieldDefinition)), RequiresDataItem]
        public class ImageListField : FieldControl, IRequiresDataItem
        {
            protected override System.Web.UI.WebControls.WebControl DescriptionControl
            {
                get { return this.Container.GetControl<Label>("description", false); }
            }
     
            protected override System.Web.UI.WebControls.WebControl ExampleControl
            {
                get { return this.Container.GetControl<Label>("example", false); }
            }
     
            protected override System.Web.UI.WebControls.WebControl TitleControl
            {
                get { return this.Container.GetControl<Label>("title", false); }
            }
     
            
            void ListView_ItemDataBound(object sender, RadListViewItemEventArgs e)
            {
                RadListViewItem radDataItem = e.Item;
                Telerik.Sitefinity.Web.UI.Fields.ImageField image = radDataItem.FindControl("imageField") as Telerik.Sitefinity.Web.UI.Fields.ImageField;
                if (image != null)
                {
                    Definition.Title = "";
                    image.Configure(Definition);
                }
            }
     
            protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
            {
                DataItem = container.GetDataItemContainer().DataItem as IDataItem;   
                if (DataItem != null)
                {
                    App.Prepare().SetContentProvider(Definition.ImageProviderName);
                    Telerik.Sitefinity.GenericContent.Model.Content data = App.WorkWith().AnyContentItem(Definition.DataFieldType, DataItem.Id).Get();
     
                    if (data != null)
                    {
                        Label label = TitleControl as Label;
                        label.Text = Title;
     
                        IQueryable<ContentLink> imageLinks = data.GetValue(DataFieldName) as IQueryable<ContentLink>;
                        if (imageLinks != null)
                        {
                            ListView.DataSource = imageLinks.Take(2).ToList();
                            ListView.ItemDataBound += new EventHandler<RadListViewItemEventArgs>(ListView_ItemDataBound);
                        }
                    }
                }
            }
     
            void ImageListField_DataBinding(object sender, EventArgs e)
            {
                Console.WriteLine(Value.ToString());
            }
     
            public override void Configure(Telerik.Sitefinity.Web.UI.Fields.Contracts.IFieldDefinition definition)
            {
                base.Configure(definition);
                ImageListFieldDefinition definition2 = definition as ImageListFieldDefinition;
                Definition = definition2;
                DataFieldName = definition2.DataFieldName;
                 
                
                Title = definition2.Title;  
                WrapperTag = definition2.WrapperTag;
                CssClass = definition2.CssClass;
                ResourceClassId = definition2.ResourceClassId;
            }
     
            private ImageListFieldDefinition Definition
            {
                get;
                set;
            }
     
            private int MaxNumberImages
            {
                get;
                set;
            }
     
            protected override string LayoutTemplateName
            {
                get { return layoutTemplateName; }
            }
     
            private const string layoutTemplateName = "Pintek.Modules.Businesses.Web.Controls.ImageListField.ascx";
     
            private RadListView ListView
            {
                get { return this.Container.GetControl<RadListView>("listView", true); }
            }
     
            private IDataItem dataItem;
            public IDataItem DataItem
            {
                get { return dataItem; }
                set { dataItem = value; }
            }
        }

    I thought having the RequiresDataItem attribute and Implementing IRequireDataItem would give my class access to the DataItem being bound to my control. However, this does not seem to be the case. Can you help me figure out what I am doing wrong?

    Thanks,
    Bobby

     

  2. Lubomir Velkov
    Lubomir Velkov avatar
    688 posts
    Registered:
    03 Nov 2014
    17 Jan 2012
    Link to this post
    Hi Bobby,

    You could use some logic like this:

    protected override void OnDataBinding(EventArgs e)
    {
        base.OnDataBinding(e);
        var container = this.GetDataItemContainer();
        object dataItem = null;
     
        if (container != null)
        dataItem = container.DataItem;
     
        if (dataItem != null)
        {
        var propDescr = TypeDescriptor.GetProperties(dataItem)[this.DataFieldName];
     
        // Catch the exception in the front end, propagate the exception in the backend
        if (this.IsDesignMode())
        {
            this.Value = propDescr.GetValue(dataItem);
        }
        else
        {
            try
            {
                this.Value = propDescr.GetValue(dataItem);
            }
            catch { }
        }
        this.DataItem = dataItem as IDataItem;
        this.BoundOnServer = true;
        }
    }


    Regards,
    Lubomir Velkov
    the Telerik team
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. Bobby
    Bobby avatar
    56 posts
    Registered:
    11 Feb 2009
    29 Jan 2012
    Link to this post
    Hi,

    I have tried your suggestion and I have not been able to get it to work. So, I am going to take a step back and explain my goal and ask you the best way to accomplish my goal. I want to associate one or more images with an item. For example, for a User object can have several Images associated with it. I have setup my relationship using OpenAccess to mimic the following sudo code.

    public Class User{
        public List<Image> Images;
    }
    I want to display this images for a user and allows them to add, edit or delete their associated images. I see that you guys have a MultiImageField control but as I understand it, that control is only valid for Products for ecommerce. I want to mimic this behavior for any object that wants to have associated images. With everything that I have tried, I am unable to get the DataItem for the field control. The DataItem in this example would be the User object. As shown in my example below, I have marked by field control to require the DataItem and it also implements the IRequiredDataItem interface. So, there must be something that I don't understand and I was hoping you could help me find a solution. Am I going about this the right way and if so, could you help me understand where I am going wrong?


    Thanks,
    Bobby
  4. Lubomir Velkov
    Lubomir Velkov avatar
    688 posts
    Registered:
    03 Nov 2014
    01 Feb 2012
    Link to this post
    Hi Bobby,

    Here is a sample implementation of how to get a reference to the DataItem during the OnDataBinding event -

    protected override void OnDataBinding(EventArgs e)
    {
        base.OnDataBinding(e);
        var container = this.GetDataItemContainer();
        object dataItem = null;
     
        if (container != null)
        dataItem = container.DataItem;
     
        if (dataItem != null)
        {
        var propDescr = TypeDescriptor.GetProperties(dataItem)[this.DataFieldName];
     
                // Catch the exception in the front end, propagate the exception in the backend
                if (this.IsDesignMode())
                {
                    this.Value = propDescr.GetValue(dataItem);
                }
                else
                {
                    try
                    {
                        this.Value = propDescr.GetValue(dataItem);
                    }
                    catch { }
                }
        this.DataItem = dataItem as IDataItem;
        this.BoundOnServer = true;
        }
    }

    Kind regards,
    Lubomir Velkov
    the Telerik team
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  5. Bobby
    Bobby avatar
    56 posts
    Registered:
    11 Feb 2009
    04 Feb 2012
    Link to this post
    Hi again,

    I am using the code but I am not having any luck getting the DataItem. The OnDataBinding function never gets called. I am sure there is something that I am missing on how to get the DataItem. So, I guess my question is, when and how does the DataBinding function get called. Since, this is an override, I would expect it be be called automatically. Is there something that I need to do when creating the FieldControlDefinitionElement that alerts my control of the DataItem? Below is my latest code. I have attached my field control code below along with your suggestion, unless I am missing something, this code does not give me the DataItem. Can you please help. Does my custom code below work for you? Any help would be appreciated.

    Thanks,
    Bobby

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Telerik.Sitefinity.Web.UI.Fields;
    using Telerik.Sitefinity.Web.UI.Fields.Enums;
    using System.Web.UI.WebControls;
    using Telerik.Sitefinity.Data;
    using Telerik.Sitefinity.Model;
    using Telerik.Web.UI;
    using Telerik.Sitefinity;
    using Telerik.Sitefinity.Model.ContentLinks;
    using System.Web.UI;
    using Telerik.Sitefinity.Web.UI.Fields.Definitions;
    using Telerik.Sitefinity.Web.UI.Fields.Contracts;
    using Telerik.Sitefinity.Web;
    using Telerik.Sitefinity.Web.UI.Fields.Config;
    using System.ComponentModel;
    using Telerik.Sitefinity.Web.UI;
    using Telerik.Sitefinity.Utilities.TypeConverters;
    using Telerik.Sitefinity.Web.Configuration;
    using Telerik.Sitefinity.Configuration;
    using Telerik.Sitefinity.Localization;
    using Telerik.Sitefinity.Modules.Libraries;
    using Telerik.Sitefinity.Web.Services;
    using Telerik.Sitefinity.Modules.Libraries.Images;
    using System.Web.UI.HtmlControls;
    using System.Web;
     
    namespace Pintek.Modules.Businesses.Web.Controls
    {
        [FieldDefinitionElement(typeof(ImageListFieldElement)), RequiresDataItem]
        public class ImageListField : FieldControl, IRequiresDataItem
        {
            private const string ajaxUploadScript = "Telerik.Sitefinity.Resources.Scripts.ajaxupload.js";
            private bool? boundOnServer;
            private Type dataFieldType;
            private IDataItem dataItem;
            private bool displayEmptyImage;
            private const string fieldDisplayModeScript = "Telerik.Sitefinity.Web.UI.Fields.Scripts.FieldDisplayMode.js";
            private const string imageFieldModeScript = "Telerik.Sitefinity.Web.UI.Fields.Scripts.ImageFieldUploadMode.js";
            private const string imageFieldScript = "Telerik.Sitefinity.Web.UI.Fields.Scripts.ImageField.js";
            private const string jqueryUIScript = "Telerik.Sitefinity.Resources.Scripts.jquery-ui-1.8.8.custom.min.js";
     
            private const string reqDataItemScriptFileName = "Telerik.Sitefinity.Web.UI.Fields.Scripts.IRequiresDataItem.js";
            private ImageFieldUploadMode uploadMode;
            private const string uploadServiceUrl = "~/Telerik.Sitefinity.AsyncImageUploadHandler.ashx";
            private static readonly string layoutTemplateName;
     
            private const string imageListFieldScript = "Pintek.Modules.Businesses.Web.Controls.ImageListField.js";
     
            static ImageListField()
            {
                layoutTemplateName = "Pintek.Modules.Businesses.Web.Controls.ImageListField.ascx";
            }
     
            public ImageListField()
            {
                this.displayEmptyImage = true;
            }
     
            protected override void OnDataBinding(EventArgs e)
            {
                base.OnDataBinding(e);
                var container = this.GetDataItemContainer();
                object dataItem = null;
     
                if (container != null)
                    dataItem = container.DataItem;
     
                if (dataItem != null)
                {
                    var propDescr = TypeDescriptor.GetProperties(dataItem)[this.DataFieldName];
     
                    // Catch the exception in the front end, propagate the exception in the backend
                    if (this.IsDesignMode())
                    {
                        this.Value = propDescr.GetValue(dataItem);
                    }
                    else
                    {
                        try
                        {
                            this.Value = propDescr.GetValue(dataItem);
                        }
                        catch { }
                    }
                    this.DataItem = dataItem as IDataItem;
                    this.boundOnServer = true;
                }
            }
     
            public override void Configure(IFieldDefinition definition)
            {
                base.Configure(definition);
                IMultiImageFieldDefinition definition2 = definition as IMultiImageFieldDefinition;
                if (definition2 != null)
                {
                    this.ImageProviderName = definition2.ImageProviderName;
                    this.ProviderNameForDefaultImage = definition2.ProviderNameForDefaultImage;
                    this.DefaultImageId = definition2.DefaultImageId;
                    this.MaxWidth = definition2.MaxWidth;
                    this.MaxHeight = definition2.MaxHeight;
                    this.DataFieldType = definition2.DataFieldType;
                    this.DefaultSrc = definition2.DefaultSrc;
                    this.DisplayEmptyImage = definition2.DisplayEmptyImage;
                }
            }
     
            public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
            {
                ScriptControlDescriptor descriptor = base.GetScriptDescriptors().Last<ScriptDescriptor>() as ScriptControlDescriptor;
                return new ScriptControlDescriptor[] { descriptor };
            }
     
            public override IEnumerable<ScriptReference> GetScriptReferences()
            {
                string fullName = typeof(ImageListField).Assembly.FullName;
                string name = Config.Get<ControlsConfig>().ResourcesAssemblyInfo.Assembly.GetName().Name;
     
                List<ScriptReference> list = new List<ScriptReference>(base.GetScriptReferences()) {
                    new ScriptReference("Telerik.Sitefinity.Web.UI.Fields.Scripts.IRequiresDataItem.js", name)
                };
     
                ScriptReference item = new ScriptReference("Telerik.Sitefinity.Resources.Scripts.jquery-ui-1.8.8.custom.min.js", name);
                list.Add(item);
                ScriptReference reference2 = new ScriptReference("Telerik.Sitefinity.Resources.Scripts.ajaxupload.js", name);
                list.Add(reference2);
                ScriptReference reference3 = new ScriptReference(imageListFieldScript, fullName);
                list.Add(reference3);
                ScriptReference reference4 = new ScriptReference("Telerik.Sitefinity.Web.UI.Fields.Scripts.FieldDisplayMode.js", fullName);
                list.Add(reference4);
                return list;
            }
     
            protected override string LayoutTemplateName
            {
                get { return layoutTemplateName; }
            }
     
            [TypeConverter(typeof(StringTypeConverter))]
            public Type DataFieldType
            {
                get
                {
                    return this.dataFieldType;
                }
                set
                {
                    this.dataFieldType = value;
                }
            }
     
            public IDataItem DataItem
            {
                get
                {
                    return this.dataItem;
                }
                set
                {
                    this.dataItem = value;
                }
            }
     
            public string DefaultAlt { get; set; }
            public Guid DefaultImageId { get; set; }
            public string DefaultSrc { get; set; }
     
            protected override WebControl DescriptionControl
            {
                get
                {
                    return null;
                }
            }
     
            public bool DisplayEmptyImage
            {
                get
                {
                    return this.displayEmptyImage;
                }
                set
                {
                    this.displayEmptyImage = value;
                }
            }
     
            protected override WebControl ExampleControl
            {
                get
                {
                    return null;
                }
            }
     
            public string ImageProviderName { get; set; }
     
            public int? MaxHeight { get; set; }
            public int? MaxWidth { get; set; }
            public string ProviderNameForDefaultImage { get; set; }
     
            protected override void InitializeControls(GenericContainer container)
            {
                 
            }
        }
    }
     
  6. Boe
    Boe avatar
    8 posts
    Registered:
    17 Nov 2011
    07 Feb 2012
    Link to this post
    Here's what I have gathered from trying to do something similar...
    The databinding doesn't happen on the server side in the backend tools. That is taken care of on the client side by the prototype scripts. As far as I can see, the only time the OnDatabinding event will fire is when the control is in read mode on a read only page. I am still working on a solution to this problem. I'm still a little frustrated that something that would've been 6 lines of code on any other site is at 250+ lines right now... and I still haven't gotten to the final solution.
  7. Lubomir Velkov
    Lubomir Velkov avatar
    688 posts
    Registered:
    03 Nov 2014
    09 Feb 2012
    Link to this post
    Hello Bobby,

    Have you tried overriding OnPreRender or InitializeControls and there use this code

    var container = this.GetDataItemContainer();
    object dataItem = null;
     
    if (container != null)
    dataItem = container.DataItem;

    The GetDataItemContainer method is an extension method in the Telerik.Sitefinity.Web namespace. It should initialize the dataItem properly.

    All the best,
    Lubomir Velkov
    the Telerik team
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
7 posts, 0 answered