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

Forums / Developing with Sitefinity / Howto Guide: Add Code behind to a Sitefinity Widget Template

Howto Guide: Add Code behind to a Sitefinity Widget Template

24 posts, 3 answered
  1. Stephen
    Stephen avatar
    4 posts
    Registered:
    27 Apr 2012
    04 Jun 2012
    Link to this post
    This is something my colleague figured out and is going to be invaluable to us in all our developments.  The ability to use Sitefinity built-in "Widget Template" functionality, and then setting the codebehind file to use.

    NB: Not sure if this is "Sitefinity Approved" but it certainly works, and seems a great deal better than any other solution I've tried (including the OpenAccessDataProvider,1283719324jkhdskf12384kjh4.ascx method - people who have used this will know what I'm talking about!!)

    1) Add in your Visual Studio solution, a Folder - name doesn't matter, e.g., "WidgetTemplates", then (if you want) a subfolder to keep things organised, e.g., "BlogPostList"

    2) Inside this subfolder, create a blank .CS file that is going to be called by your Widget Template.  My example calls it "BlogPostList.cs".  This needs to be the same structure as if it was code-behind to a Web User Control.  Here below is my whole code ATM that adds a custom ItemDataBound handler, to display images in my Blog Post List widget template.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Telerik.Sitefinity.Web.UI;
    using Telerik.Web.UI;
    using Telerik.Sitefinity;
    using Telerik.Sitefinity.Blogs.Model;
    using Telerik.Sitefinity.Model;
     
    namespace SitefinityWebApp.WidgetTemplates.BlogPostList {
        public partial class BlogPostList : System.Web.UI.UserControl {
            protected override void OnInit(EventArgs e) {
                base.OnInit(e);
     
                var repeater = (RadListView)this.FindControl("Repeater");
                repeater.ItemDataBound += new EventHandler<RadListViewItemEventArgs>(repeater_ItemDataBound);
            }
     
            void repeater_ItemDataBound(object sender, RadListViewItemEventArgs e) {
                if (e.Item is RadListViewDataItem) {
                    var args = (RadListViewDataItem)e.Item;
                    var blogPost = (BlogPost)args.DataItem;
                    var imagePath = DataExtensions.GetValue<String>(blogPost, "Image");
                    var imageCtl = (Image)e.Item.FindControl("imgBlogImage");
     
                    if (!string.IsNullOrEmpty(imagePath) && imageCtl != null) {
                        imageCtl.ImageUrl = imagePath;
                    } else if (imageCtl != null) {
                        imageCtl.Visible = false;
                    }
                }
            }
        }
    }

    3) In the Backend, go to Administration -> Widget Templates -> The Template you want to interact with.  (My example will use a very slightly customised Widget Template for Blog Post lists - close enough to Default to not matter, but you can use this method on any Widget Template).  Below is the Widget Template code:
    <%@ Control Language="C#" Inherits="SitefinityWebApp.WidgetTemplates.BlogPostList.BlogPostList" %>
    <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.ContentUI" Assembly="Telerik.Sitefinity" %>
    <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.Comments" Assembly="Telerik.Sitefinity" %>
    <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %>
    <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %>
    <%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
    <%@ Import Namespace="Telerik.Sitefinity" %>
     
    <telerik:RadListView ID="Repeater" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false">
      <LayoutTemplate>
        <sf:ContentBrowseAndEditToolbar ID="MainBrowseAndEditToolbar" runat="server" Mode="Add"></sf:ContentBrowseAndEditToolbar>
        <ul class="sfpostsList sfpostListTitleDateContent">
          <asp:PlaceHolder ID="ItemsContainer" runat="server" />
        </ul>
      </LayoutTemplate>
     
      <ItemTemplate>
        <li class="sfpostListItem">
          <h2 class="sfpostTitle">
            <sf:DetailsViewHyperLink TextDataField="Title" ToolTipDataField="Description" runat="server" />
          </h2>
               
          <div class="sfpostAuthorAndDate">
            <asp:Literal ID="Literal2" Text="<%$ Resources:Labels, By %>" runat="server" />
            <sf:PersonProfileView runat="server" />
            <asp:Literal ID="Literal3" runat="server" Text=" on " />
            <sf:FieldListView ID="PostDate" runat="server" Format=" {PublicationDate.ToLocal():dd MMM, yyyy}" />
            <sf:CommentsBox ID="itemCommentsLink" runat="server" CssClass="sfpostCommentsCount"/>
          </div>
           
          <div class="imgWrap">
            <asp:Image id="imgBlogImage" runat="server" />
          </div>
           
          <sf:FieldListView ID="PostContent" runat="server" Text="{0}" Properties="Content" WrapperTagName="div" WrapperTagCssClass="sfpostContent" />
          <sf:DetailsViewHyperLink Text="Continue reading this blog post" runat="server" />
          <sf:ContentBrowseAndEditToolbar ID="BrowseAndEditToolbar" runat="server" Mode="Edit,Delete,Unpublish"></sf:ContentBrowseAndEditToolbar>
        </li>
      </ItemTemplate>
    </telerik:RadListView>
    <sf:Pager id="pager" runat="server"></sf:Pager>
    <asp:PlaceHolder ID="socialOptionsContainer" runat="server" />

    4) Add at the top of the Widget Template, the reference to Inherits:
    <%@ Control Language="C#" Inherits="SitefinityWebApp.WidgetTemplates.BlogPostList.BlogPostList" %>

    That's it!  My codebehind now has bound a custom event handler to the RadListView and sets the ImageUrl by getting the data from a Custom Field in the Backend.  This is just a tiny taste that could easily be done in other ways, but this ability to use server side code with a Widget Template like this is so powerful...

    Immediate examples that I'm going to extend:
    1) Creating a dynamically generated Summary.  Instead of having to set the "Summary" field in the Backend, I plan to get the whole Blog Post article, shorten it to ~100 characters, add "..." at the end - Instant Summary!

    2) Instead of just using ImageUrl, I need to implement AltText also.  I'll lookup the image (by Url at this stage, but hopefully by Guid) and grab the AltText from the Image object.

    3) Customising the "Read more" <sf:DetailsViewHyperLink Text="Continue reading this blog post" runat="server" />.  Instead of "Continue reading this blog" I want it to say "Continue reading 'Title'

    I'm sure there's hundreds of smarter things to do with this as well, it's very exciting.  Would love any feedback, especially from Sitefinity devs as to why this is a good or bad approach?

    Answered
  2. Laura
    Laura avatar
    311 posts
    Registered:
    25 Feb 2008
    15 Jun 2012
    Link to this post
    This is great. Thanks for sharing! 
    Looking forward to the feedback from Sitefinity!
  3. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    24 Jul 2012
    Link to this post
    This is a fantastic find, and deserves a bump....way more elegant than any of the other solutions! :) *cough*SfCtrlPresentation folder*cough*
  4. Charley
    Charley avatar
    3 posts
    Registered:
    15 Aug 2012
    05 Sep 2012
    Link to this post
    Thanks for sharing you get another bump.  :)
  5. Markus
    Markus avatar
    2763 posts
    Registered:
    25 Nov 2005
    05 Sep 2012
    Link to this post
    Dear Stephen

    Great. I was anoyed by the search results summery. I might now simply change it to diplay the description of the page. 

    I don't know what it means to give a bump. But sure would +1 or like it on social medias :-)

    Markus

    PS: Since the widget templates are in my opinion rather developer orientated how about getting codebehind files out of the box?
  6. Jacques
    Jacques avatar
    427 posts
    Registered:
    28 Jun 2007
    04 Apr 2013 in reply to Stephen
    Link to this post
    Hi Stephen,

    Thanks for that, exactly what I'm looking for. Would this affect any of the other code associated with the widget already? Just wondering if for example the Blog post's comment function would stop working because you're essentially binding the widget template to a different class.

    I don't have a great understanding of WebForms templates, which might be why I'm asking the question. Sometimes it seems to me that templating allows you to associate two objects with a control?

    Regards,
    Jacques
  7. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    04 Apr 2013 in reply to Jacques
    Link to this post
    @J.Hoventer
      Any widget using that template would then run the associated codebehind yeah...however keep in mind you aren't binding it to another class, but almost like adding a "layer".

    The control is still SimpleView based, and all the code it runs, it will continue to run.  This usercontrol workaround lets you hook into the page events and reference controls on the page.

    The simpleview is the root control, which references a "View" which is the ascx...this is almost like giving the ascx it's own seperate codebehind (if that makes sense)

    Steve
    Answered
  8. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    04 Apr 2013
    Link to this post
    Thanks @Steve.

    I'm not that clever, my colleagues invented this - I just posted it and take the credit!!  Hence I'm not exactly sure how this all hangs together, but I concur with the end result:

    * You get the default Sitefinity code runs first
    * Any code you add using this method runs second and is the "master"

    That's how I think of it anyway...
  9. Patrick Dunn
    Patrick Dunn avatar
    237 posts
    Registered:
    03 Nov 2014
    09 Apr 2013
    Link to this post
    Hello,

     Steve is right on track with this and this is the best method to add additional logic to default controls.

    Regards,
    Patrick Dunn
    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
  10. Stacey
    Stacey avatar
    291 posts
    Registered:
    18 Oct 2012
    16 Apr 2013
    Link to this post
    Has anyone done something like this with widget templates based off dynamic modules?

    Right now the only way I can get code behind working for a dynamic widget template is by mapping it like described in this blog post.

    http://www.sitefinity.com/blogs/jen-pelevas-blog/2013/03/31/how-to-create-lightbox-gallery-in-a-custom-module
  11. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    16 Apr 2013 in reply to Stacey
    Link to this post
    Absolutely!  All the time.. But not for a while, we're more into using custom EVAL functions at this time.

    What seems to be the trouble?
  12. Stacey
    Stacey avatar
    291 posts
    Registered:
    18 Oct 2012
    16 Apr 2013 in reply to Stephen2
    Link to this post
    I will be away from the project for a couple days so I can't get the exact error right now, but it was something about a template missing a dynamicDetails container ID error.

    template could not find a dynamic details container with ID something...   Not very helpful I know, but I will update this when I am back at the computer with the actual project.
  13. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    16 Apr 2013 in reply to Stacey
    Link to this post
    Oh, cool... Sounds like you may have changed the ID of the RadListView?

    If I drop a default widget on, in List mode, but change:
    <telerik:RadListView ID="dynamicContentListView"
    to
    <telerik:RadListView ID="dynamicContentListView2"

    I get this error:
    A required control was not found in the template for "~/SfCtrlPresentation/OpenAccessDataProvider,b693ab6499f94fb49add92195f062685.ascx". The control must be assignable from type "Telerik.Web.UI.RadListView" and must have ID "dynamicContentListView".

    Suspect your problem is something similar.  Lots of the stuff in widget templates has to be left default, e.g., Sitefinity breaks when:
    * Renaming or removing RadListView
    * Removing <sf:Pager>
    etc...

    Hope that helps.

    Answered
  14. Patrick Dunn
    Patrick Dunn avatar
    237 posts
    Registered:
    03 Nov 2014
    18 Apr 2013
    Link to this post
    Hi,

     Stephen is correct.

    This method inherits from the existing widget so the requirements outlined by it are still in place. It is a custom user control where the necessary components are dictated by code. For example like this:

    public HyperLink SeeAllContentLink
            {
                get
                {
                    return this.Container.GetControl<HyperLink>("SeeAllContentLink", false);
                }
            }

    for each necessary control on the template. Overriding does not remove these relationships so you must keep those controls on the template with their original ID but you can add additional controls. All the best,
    Patrick Dunn
    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
  15. Stacey
    Stacey avatar
    291 posts
    Registered:
    18 Oct 2012
    18 Apr 2013 in reply to Patrick Dunn
    Link to this post
    Thanks Stephen and Patrick,

    Your recommendations lead me to the real issue, which in the end is pretty much the same situation.  I am smacking myself for not catching this....one of those days where I was over complicating what I was trying to do.

    So the first problem is that I was trying to use a RadListView on a details view template.  So the error was in fact complaining that it was missing an assignable type for the DynamicDetailContainer with ID "detailContainer".  

    I went back into my widget template and added <sf:DynamicDetailContainer ID="detailContainer" runat="server"> which took care of my problem.


    Thank you both for the help.  
  16. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    18 Apr 2013 in reply to Stacey
    Link to this post
    No problem mate.  Glad it worked out :)
  17. Ryan
    Ryan avatar
    13 posts
    Registered:
    01 Dec 2010
    10 Jun 2013
    Link to this post
    So it appears that Sitefinity 6 no longer has an Image in a BlogPost, and I'm getting an error on :

    var imagePath = DataExtensions.GetValue<String>(blogPost, "Image");

    So to get this working I replaced with :

    //var imagePath = DataExtensions.GetValue<String>(blogPost, "Image");
                    var imagePath = DataExtensions.GetValue<Lstring>(blogPost, "Content").ToString();
     
                    if (imagePath.Contains("<img "))
                    {
     
                        imagePath = imagePath.Substring(imagePath.IndexOf("<img "));
     
                        imagePath = imagePath.Substring(imagePath.IndexOf("src=\"") + 5);
     
                        imagePath = imagePath.Substring(0, imagePath.IndexOf("\""));
     
                    }
                    else
                    {
                        imagePath = "";
                    }

    To get the image path out of the content.  Can anyone confirm that Image has been removed from BlogPost in Sitefinity 6, or Does someone have a better way of getting the image out of the blog?
  18. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    10 Jun 2013 in reply to Ryan
    Link to this post
    afaik "Image" isn't a native field in a SF blog post...?  At least has never been there in my instances
  19. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    10 Jun 2013
    Link to this post
    Steve is correct, Image is not and has not ever been a native field for Blogs.  We use the ImageSelectorField that we took from a blog post or sample somewhere...
  20. Geoffrey
    Geoffrey avatar
    24 posts
    Registered:
    05 Nov 2014
    20 Jan
    Link to this post

    So I got this working for ProductDetail page.

    The problem that I am having is that I need to manipulate properties of the product for the page I am viewing.  So far no matter what I am trying I am unable to get to the product that I am currently viewing.

    Can anyone point me to what I am missing?

  21. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    20 Jan in reply to Geoffrey
    Link to this post
    Can you paste in what you have? 
  22. Avi
    Avi  avatar
    2 posts
    Registered:
    05 Mar 2013
    02 Jun
    Link to this post
    Is this how to still valid and working in version 9. I have tried to implement it and it breaks the widget template. I dont think i have made a mistake...
  23. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    02 Jun
    Link to this post

    It's amazing how far Sitefinity has come since this post was written so long ago...  Project Feather is the best thing ever in Sitefinity Dev, since Dynamic Modules.

     

    I'm sorry to give an answer that is almost certainly not helpful to you in your current situation - you should 100% learn Project Feather and do whatever you're trying to do now using it.

     

    However, if you post your WidgetTemplate & Code behind class we can see if anything looks awry.  Can't see why this wouldn't work in 9+ but as you can imagine, haven't done this method for a while now.

  24. Geoffrey
    Geoffrey avatar
    24 posts
    Registered:
    05 Nov 2014
    02 Jun in reply to Steve
    Link to this post

    Missed your question, sorry.

     

    In the end I linked into the data binding event that was available on the page.  At that point I was able to hook into the product object and therefore I was able to access the data needed.  

     

    Thanks.

24 posts, 3 answered