+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Extend the Image Selector for Content Items with Filtering by Album

by Slavo Ingilizov

A while ago I wrote a blog post, showing you how you can implement your own widget to associate any content item with an image. A lot of people had interest in such a task, at least judging by the comments all of you left. With this next installment, I’m going to extend the image selector and show you how to implement the two most requested features:

  • Filtering the images by album
  • Extracting the image selector in its own project/assembly.

To keep things short, I’ll assume you’ve read the other blog post. Before we move on with the implementation, take a look at the following screencast, showing you the end result: Image Selector for News with Album Filtering.

You can download the source code for this example from here.

For the sake of simplicity, let’s start with bullet number 2. Unlike the previous blog post, the whole image selector is extracted in its own assembly. The structure of the project is somewhat different from the one in the previous blog post. Because of this I recommend that you start from scratch, even if you have used the old project. Here are the steps you need to follow:

Installation Instructions

  1. Download the source code and open it.
  2. Extract the ThumbnailSelectorField folder from the archive to a location of your choice. I recommend that it is a sibling folder of the one containing your web application. My files after the extraction look like this:
    FileStructure
  3. Open your web project in Visual Studio
  4. Add an existing project to the solution, and locate the ThumbnailSelectorField from the extracted folder. After this step, your visual studio solution should look like this:
    SolutionStructure
  5. Extract the Global.asax files from the archive to the root folder of your web project. Include them in the Visual Studio project (if you don’t see them show all files from the toolbar button in Solution Explorer).
  6. Include a project reference to the ThumbnailSelectorField project in your web project.
  7. At this point your solution should build without errors. Save the solution file in the root web application folder if it prompts you to do it.
  8. Run the project, and create a custom field for a chosen module, as shown in the screencast. (Setup the database connection once prompted, if you haven’t done this already).
    1. The custom field should be of type Short Text.
    2. The custom type for the UI widget should be Telerik.Sitefinity.Samples.SimpleImageField.
  9. Upload some images and create some albums if there aren’t any.
  10. All done. You should be able to assign images to each content item.

Embedded templates and scripts

As you can see, the downloaded class library project contains all files for the image selector, including the scripts and templates. The scripts and templates are embedded resources, not regular files (you can see this in the BuildAction property of each file). Because of this, we need to do some plumbing.

  • Register a prefix to load the widget templates (ASCX files) as embedded templates from the new assembly.
    This is done by the code in Global.asax. More information for widget templates and how they are used by Sitefinity can be found here.
  • Let ASP.NET know it has to load scripts from the assembly and send them to the client
    If you have client code as an embedded resource, you can directly instruct ASP.NET to serve it to the browser. Same goes for CSS files. This is done by adding an entry for each file in the AssemblyInfo.cs file of the project. The source code you have downloaded already has the needed entries:

Our image selector uses its own CSS, and we need to change the code that loads it, to get it from the embedded resource, rather than an actual file (like it used to be in the previous version). This is done by the following code in SimpleImageSelector.cs:

Filtering by Album

If you have followed the above instructions correctly, then you should have a widget working from its own project. With this, one of the requested features is done. The other requirement involves writing a little more code. Implementing filtering by album can be broken down into the following steps:

  • Include a control to display a list of albums in the template for SimpleImageSelector
  • Bind the list of albums using a GenericCollectionBinder
  • Handle the click to filter the list of images

The first step is simple. We only need a placeholder, where the binder will generate the markup for all albums. In our case this is a UL tag. Here’s the whole selector with the two placeholders – one for a list of albums, and one for a list of images (all DIV tags are there for easier styling and have no functional role):

The binding of the album list is very similar to the binding of the images list. We just need another instance of the GenericCollectionBinder. The only things we have to change are the service it binds to (Albums instead of images), and the markup for displaying a single item:

We now have everything we need in the template, time to write the code that does the actual binding. In the client component for the selector, there is a new property for the new album binder. We only need to call the DataBind() method.

As you can see, we also take note of what is the original URL for the image service. The reason is that when a single album is clicked by the user, the URL changes. Each next click changes the URL by appending the album ID to the original URL (to only retrieve images in that album). This is done, when handling the click command:

When an album is clicked, we get its ID, update the URL of the service to include this ID, and then rebind the list of images. That’s all there is to it.

One more small update in the selector is that instead of URLs, it now keeps the IDs of selected images. The benefit this gives us is that if the URL of an image changes, the selector will not break and will still show the correct image.

If you are not the type of person to implement all the above code, just download the project and follow the installation instructions. I’ve included the implementation as a showcase of working with binders and services. There are easier ways to achieve the same scenario by using our built-in selectors, but this is a topic for another blog post. Happy coding! Let us know what you think in the comments.

16 comments

Leave a comment
  1. Sitefinity Dev Jun 11, 2012
    Hello,
    I have followed the same steps mentioned in this blog, but not able to render image on my page.

    Thanks
  2. Sitefinity Dev Jun 12, 2012
    Hello,
    Able to run the code successfully after making one change in code file "SimpleImageField.cs"
     
    //this.ImageControl.ImageUrl = "~/" + url + "&size=100";
    this.ImageControl.ImageUrl =url + "&size=100";

    Thanks 
  3. Cagri Jun 13, 2012
    Hi, 

    I have problem running this with sitefinity 5.0

    I get errors.

    Have you made it to work with 5.0?

    Error 1 The type or namespace name 'Samples' does not exist in the namespace 'Telerik.Sitefinity' (are you missing an assembly reference?) C:\Program Files\telerik\Sitefinity 5.0\Projects\minderWeb\Global.asax.cs 23 81 SitefinityWebApp

  4. Cagri Jun 13, 2012
    Hi, 

    I have problem running this with sitefinity 5.0

    I get errors.

    Have you made it to work with 5.0?

    Error 1 The type or namespace name 'Samples' does not exist in the namespace 'Telerik.Sitefinity' (are you missing an assembly reference?) C:\Program Files\telerik\Sitefinity 5.0\Projects\minderWeb\Global.asax.cs 23 81 SitefinityWebApp

  5. Lalit Jun 20, 2012
    Hello Cargi,
    Extract the attached zip file "ThumbnailSelectorField "
    at the specified location i.e parallel to "SitefinityWebApp" folder and include "ThumbnailSelectorField" project in your solution. Include ThumbnailSelectorField. 
    dll reference in your main project . It will resolve your issue.
    Please let me know in case you are facing any issue.

    Thanks 

  6. Howard Dec 12, 2012
    Can we use this in the blog post instead of News module?

    I followed the installation instructions but likely I missed something here because when I open the module, I get the following error message

    Cannot find template "~/ThumbnailSelector/ThumbnailSelectorField.SimpleImageField.SimpleImageField.ascx"

    Thanks
  7. Umar Jan 09, 2013
    Followed all the instructions and got this error while adding the custom field.


    Server Error in '/surf' Application.

    Type "Telerik.Sitefinity.Samples.SimpleImageFieldElement, SitefinityWebApp" cannot be resolved.



    Description: An unhandled exception occurred during
    the execution of the current web request. Please review the stack trace
    for more information about the error and where it originated in the
    code.





    Exception Details: System.ArgumentException: Type "Telerik.Sitefinity.Samples.SimpleImageFieldElement, SitefinityWebApp" cannot be resolved.



    Source Error:








    An unhandled exception was generated during the execution of the current
    web request. Information regarding the origin and location of the
    exception can be identified using the exception stack trace below.








    Stack Trace:






    [ArgumentException: Type "Telerik.Sitefinity.Samples.SimpleImageFieldElement, SitefinityWebApp" cannot be resolved.]
    Telerik.Sitefinity.Utilities.TypeConverters.TypeResolutionService.GetType(String name, Boolean throwOnError, Boolean ignoreCase) +1317
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadCollectionElement(ConfigElementCollection collection, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo) +1021
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadElement(ConfigElement element, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo, Boolean isNew, Boolean validateTagName) +323
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadPropertyElement(ConfigElement element, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo) +577
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadElement(ConfigElement element, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo, Boolean isNew, Boolean validateTagName) +355
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadCollectionElement(ConfigElementCollection collection, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo) +1143
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadElement(ConfigElement element, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo, Boolean isNew, Boolean validateTagName) +323
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadPropertyElement(ConfigElement element, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo) +577
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadElement(ConfigElement element, XmlReader reader, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo, Boolean isNew, Boolean validateTagName) +355
    Telerik.Sitefinity.Configuration.Data.XmlConfigProvider.LoadElement(String relativeFilePath, Func`2 elementFactory, ConfigPolicyHandler policyHandler, String policyName, UpgradingInfo upgradingInfo, Boolean isDefault) +251
    Telerik.Sitefinity.Configuration.Data.<>c__DisplayClass14.<LoadCollectionElement>b__d() +101
    Telerik.Sitefinity.Configuration.<>c__DisplayClass1.<Unload>b__0() +24
    System.Lazy`1.CreateValue() +455
    System.Lazy`1.get_Value() +14390282
    Telerik.Sitefinity.Configuration.ConfigElementLazyItem`1.get_Element() +100
    System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +265
    System.Linq.WhereEnumerableIterator`1.MoveNext() +148
    System.Linq.Buffer`1..ctor(IEnumerable`1 source) +488
    System.Linq.Enumerable.ToArray(IEnumerable`1 source) +103
    Telerik.Sitefinity.ModuleEditor.Web.Services.Model.CustomFieldsContext.GetViews(String contentTypeFullName) +1182
    Telerik.Sitefinity.ModuleEditor.Web.Services.Model.WcfDefinitionBuilder.BuildVisibleViewsInfo(Type fieldType, Type contentType, String fieldName, WcfFieldDefinition definition, String command) +103
    Telerik.Sitefinity.ModuleEditor.Web.Services.Model.WcfDefinitionBuilder.GetBaseWcfDefinition(Type fieldType, Type contentType, String fieldName, String command) +175
    Telerik.Sitefinity.ModuleEditor.Web.Services.Model.WcfDefinitionBuilder.GetWcfDefinition(Type fieldType, Type contentType, String fieldName, String command) +73
    Telerik.Sitefinity.ModuleEditor.Web.UI.CustomFieldPropertyEditor.InitializeControls(GenericContainer dialogContainer) +1100
    Telerik.Sitefinity.Web.UI.DialogBase.CreateChildControls() +92
    System.Web.UI.Control.EnsureChildControls() +189
    System.Web.UI.WebControls.CompositeControl.get_Controls() +24
    Telerik.Sitefinity.Web.UI.PropertyEditor.OnInit(EventArgs e) +61
    System.Web.UI.Control.InitRecursive(Control namingContainer) +477
    System.Web.UI.Control.AddedControl(Control control, Int32 index) +304
    Telerik.Sitefinity.Web.DialogRouteHandler.InitializeContent(Page handler, RequestContext requestContext) +414
    System.Web.UI.Control.LoadRecursive() +95
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2936

    any ideas ?











    Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.17929              

  8. Umar Jan 10, 2013

    Hi Slavo,

     

    I have double checked i have added the reference to my SitefinityWebApp Project.  

     Its still not working.

     

    Thanks

    Umar

  9. John P Feb 04, 2013

    Howard:

     You will get this error if you don't deploy the global.asax to your production server.  There is code in the code behind to support custom virtual paths that is needed by this control.

     thanks

    John

  10. Nigel Wilson Sep 20, 2013
    Hi there - I am getting the following error when clicking the "Select" button on a blog post.

    Detail":"Error executing query: Telerik.OpenAccess.RT.sql.SQLException: The incoming request has too many parameters. The server supports a maximum of 2100 parameters. Reduce the number of parameters and resend the request....

    We are running Sitefinity v6.1 

    Any suggestions please ?

    Thanks
    Nigel
  11. mansoor Sep 24, 2013
    hi,
    when i add custom field in news widget, i got below error 

    Type "Telerik.Sitefinity.Samples.SimpleImageField" cannot be resolved.

    In my solution i have added   below files:
    DetailViewShortcuts.js
    jquery.hotkeys.js
    MasterViewShortcuts.js
    style.css

     and in Assemblyinfo.cs file i have added below lines;

    [assembly: System.Web.UI.WebResource("SitefinityWebApp.ImageSelector.SimpleImageSelector.js", "application/x-javascript")]

    [assembly: System.Web.UI.WebResource("SitefinityWebApp.ImageSelector.SimpleImageField.js", "application/x-javascript")]
    [assembly: System.Web.UI.WebResource("SitefinityWebApp.ImageSelector.SimpleImageSelectorDialog.js", "application/x-javascript")]



    then why i am getting error. 
    =mansoor






  12. Shannon Sep 28, 2013
    I have got this to work, but when displaying only the GUID renders.

    Is there an issue with using this in 6.1?
  13. Thom Oct 10, 2013
    Shannon,

    I'm having the exact same problem in 6.1.

    Tracked it down to the SimpleImageField.cs file, but can't get any further:

            public override object Value
            {
                get
                {
                    var val = string.Empty;
                    switch (this.DisplayMode)
                    {
                        case FieldDisplayMode.Read:
                            val = this.ImageControl.ImageUrl;
                            break;
                        case FieldDisplayMode.Write:
                            val = this.TextBoxControl.Text;
                            break;
                    }
                    return val;
                }
                set
                {
                    if (this.ChildControlsCreated)
                    {
                        var imageId = new Guid(value as string);
                        var img = App.WorkWith().Image(imageId).Get();
                        _imageUrl = img.MediaUrl;
                        _thumbnailUrl = img.ThumbnailUrl;
                        SetImageUrl();
                        if (DisplayMode == FieldDisplayMode.Write)
                            TextBoxControl.Text = value as string;
                        base.Value = null;
                    }
                    else
                    {
                        base.Value = value;
                    }
                }
            }

    That If statement is always false, so that whole hunk of code never runs.  Not sure how to fix it from there.
  14. Thom Oct 15, 2013


    I haven't implemented it yet because I have some merging to work out, but this is the answer from Support:

    "In version 6.0 we have introduced Hierarchical libraries and this is the reason why this sample could not work as expected. Please check the attached file where you can find modified sample which is compatible with 6.x projects. Using the modified sample there should be no problems with this functionality."

    I can't attach the file because that isn't an option with the blog comments. If anyone has run into the same problem I am having and needs the solution, maybe you can contact support to get the ThumbnailSelectorField.zip file that was sent to me.
  15. colour sorter machine Jun 30, 2016
    Thanks for sharing this nice blog. I read it completely and get some interesting blog information from it.I am waiting for your new blog please share new blog information my Email id.Thanks a lot.
  16. machine vision lenses Jul 16, 2016
    Thanks for sharing this nice blog. I read it completely and get some interesting blog information from it.I am waiting for your new blog please share new blog information my Email id.Thanks a lot.     

    Leave a comment