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

Download List control to group items for download by parent library

by Radoslav Georgiev
This week's Tip of the Week blog post is going to sample a custom download list control. The difference between this control and the built-in one is that the custom one is going to display the downloadable items in separate tables, broken down by parent libraries to which they belong. Bellow you can see the resulting look and feel of the control:

Custom dowloads control

To achieve this we will need to create a custom control and provide a control template for this control. In this sample I have inherited from DownloadList to utilize the existing ability to select libraries from which we wish to display items for download. What we will do is to create a custom template which has two nested repeaters. The outer one will display library name and the inned one will display content items belonging to his library. Bellow is the sample code for the CustomDonwloadList control:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.UI.WebControls;
using Telerik.Cms.Engine;
using Telerik.Cms.Engine.ContentViewFiltering;
using Telerik.Cms.Engine.WebControls;
using Telerik.Libraries;
 
/// <summary>
/// Summary description for CustomDownloadList
/// </summary>
public class CustomDownloadList: DownloadList
{
    //set template path for the control template
    public override string ItemListTemplatePath
    {
        get
        {
            return "~/CustomControls/ControlTemplates/CustomDonwloadList.ascx";
        }
        set
        {
            base.ItemListTemplatePath = value;
        }
    }
    public override string ProviderName
    {
        get
        {
            return "Libraries";
        }
        set
        {
            base.ProviderName = value;
        }
    }
    //here we populate our libraries repeater with selected libraries
    protected override void CreateContentList()
    {
        ContentFilterBuilder filterBuilder = new ContentFilterBuilder(this);
        libraryManager = new LibraryManager();
        IList libraries =  null;
        Guid[] parentIds = filterBuilder.ParseParentsFilter();
        if (parentIds.Count()>0)
        {
            List<ILibrary> libs = new List<ILibrary>();
            foreach (Guid id in parentIds)
            {
                libs.Add(libraryManager.GetLibrary(id));
            }
            libraries = libs.ToList();
        }
        else
        {
            libraries = libraryManager.GetAllLibraries("Image", false);
        }
        //sort libraries in ascendding order by name
        IQueryable<ILibrary> librariesQ = libraries.Cast<ILibrary>().AsQueryable<ILibrary>();
        var sortedLibraries = from list in librariesQ
                              orderby list.Name
                              select list;
        LibrariesRepeater.ItemDataBound+=new RepeaterItemEventHandler(LibrariesRepeater_ItemDataBound);
        LibrariesRepeater.DataSource = sortedLibraries.ToList();
        LibrariesRepeater.DataBind();
    }
    //for each seleceted library create the table containing content items
    void LibrariesRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
        {
            ILibrary library = (ILibrary)e.Item.DataItem;
            if (library.ItemsCount > 0)
            {
                Literal LibraryName = (Literal)e.Item.FindControl("LibraryName");
                Repeater ItemsRepeater = (Repeater)e.Item.FindControl("itemsRepeater");
                if (ItemsRepeater != null && LibraryName!=null)
                {
                    LibraryName.Text = library.Name;
                    IList items = library.GetItems();
                    ItemsRepeater.ItemDataBound += new RepeaterItemEventHandler(ItemsRepeater_ItemDataBound);
                    ItemsRepeater.DataSource = items;
                    ItemsRepeater.DataBind();
                }
            }
        }
    }
    //set meta data for each item displayed in the downloads table
    void ItemsRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
        {
            HyperLink DownloadLink = (HyperLink)e.Item.FindControl("DownloadLink");
            Literal Title = (Literal)e.Item.FindControl("Title");
            Literal Description = (Literal)e.Item.FindControl("Description");
            Literal Extension = (Literal)e.Item.FindControl("Extension");
            Label Author = (Label)e.Item.FindControl("Author");
            Literal UploadDate = (Literal)e.Item.FindControl("UploadDate");
            Literal Size = (Literal)e.Item.FindControl("Size");
            Repeater Tags = (Repeater)e.Item.FindControl("Tags");
            HyperLink FileFileDownloadLink = (HyperLink)e.Item.FindControl("FileDownloadLink");
            IContent contentItem = (IContent)e.Item.DataItem;
            if (contentItem.MimeType.StartsWith("Video", true, CultureInfo.InvariantCulture))
            {
                DownloadLink.NavigateUrl = base.ResolveUrl(string.Format("{0}?download=true", contentItem.UrlWithExtension));
            }
            else
            {
                DownloadLink.NavigateUrl = base.ResolveUrl(contentItem.UrlWithExtension);
            }
            FileFileDownloadLink.NavigateUrl = base.ResolveUrl(string.Format("{0}?download=true", contentItem.UrlWithExtension));
            Title.Text = contentItem.GetMetaData("Name") as string;
            Description.Text = contentItem.GetMetaData("Description") as string;
            Extension.Text = contentItem.GetMetaData("Extension") as string;
            Author.Text = contentItem.GetMetaData("Author") as string;
            UploadDate.Text = contentItem.DateCreated.ToShortDateString();
            Size.Text = contentItem.GetMetaData("Size").ToString();
            long num;
            long.TryParse(Size.Text, out num);
            Size.Text = LibraryHelper.FormatSizeString(num);
            Tags.ItemDataBound += new RepeaterItemEventHandler(Tags_ItemDataBound);
            Tags.DataSource = libraryManager.GetTags(contentItem.ID);
            Tags.DataBind();
        }
    }
 
    void Tags_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
        {
            ITag dataItem = (ITag)e.Item.DataItem;
            HyperLink link = (HyperLink)e.Item.FindControl("tagLink");
            if (link != null)
            {
                link.Text = dataItem.TagName;
                link.NavigateUrl = this.GetTagUrl(dataItem, this.ItemListUrl);
            }
        }
    }
    //get refference to the libraries repeater from control template
    public Repeater LibrariesRepeater
    {
        get
        {
            return base.ListContainer.GetControl<Repeater>("librariesRepeater", false, Telerik.Framework.Web.TraverseMethod.BreadthFirst);
        }
        set
        {
            LibrariesRepeater = value;
        }
    }
 
    private LibraryManager libraryManager;
}

Now we need to provide the markup for our control template. I am going to reuse the one from the Download List Table View mode template:

<%@ Control Language="C#" %>
<%--content view controls have a requirerd Repeater control with ID="repeater" add one and set it to not visible--%>
<asp:Repeater ID="repeater" runat="server" Visible="false"></asp:Repeater>
<telerik:CssFileLink ID="CssFileLink1" FileName="~/CustomControls/ControlTemplates/librariesCommonLayout.css" Media="screen" runat="server"/>
<asp:Repeater ID="librariesRepeater" runat="server">
    <ItemTemplate>
        <p><asp:Literal ID="LibraryName" runat="server"></asp:Literal></p>
        <asp:Repeater ID="itemsRepeater" runat="server">
            <HeaderTemplate>
                <table class="sf_libraryGrid">
                    <thead>
                    <tr>
                        <th scope="col" id="TitleWrap" runat="server"><asp:Literal ID="Literal1" runat="server" Text="<%$Resources:Items_Title %>"></asp:Literal></th>
                        <th scope="col" id="ExtWrap" runat="server"><asp:Literal ID="Literal2" runat="server" Text="<%$Resources:Items_Extension %>"></asp:Literal></th>
                        <th scope="col" id="AuthorWrap" runat="server"><asp:Literal ID="Literal3" runat="server" Text="<%$Resources:Items_Author %>"></asp:Literal></th>
                        <th scope="col" id="UploadDateWrap" runat="server"><asp:Literal ID="Literal4" runat="server" Text="<%$Resources:Items_UploadDate %>"></asp:Literal></th>
                        <th scope="col" id="SizeWrap" runat="server"><asp:Literal ID="Literal5" runat="server" Text="<%$Resources:Items_Size %>"></asp:Literal></th>
                        <th scope="col" id="TagWrap" runat="server"><asp:Literal ID="Literal6" runat="server" Text="<%$Resources:Items_Tags %>"></asp:Literal></th>
                        <th scope="col" id="DownloadLinkWrap" runat="server"></th>
                    </tr>
                    </thead>
                    <tbody>
            </HeaderTemplate>
            <ItemTemplate>
                    <tr>
                        <th id="TitleWrap" runat="server" scope="row" class="sf_docTitle">
                            <asp:HyperLink ID="DownloadLink" runat="server">
                                <asp:Literal ID="Title" runat="server"></asp:Literal>
                            </asp:HyperLink>
                            <asp:Literal ID="Description" runat="server" />
                        </th>
                        <td id="ExtWrap" runat="server"><asp:Literal id="Extension" runat="server"></asp:Literal></td>
                        <td id="AuthorWrap" runat="server"><asp:Label id="Author" runat="server"></asp:Label></td>
                        <td id="UploadDateWrap" runat="server" class="sf_date">
                            <asp:Literal ID="UploadDate" runat="server" />
                        </td>
                        <td id="SizeWrap" runat="server" class="sf_size"><asp:Literal id="Size" runat="server"></asp:Literal></td>
                        <td id="TagWrap" runat="server">
                            <asp:Repeater id="Tags" runat="server">
                                <ItemTemplate>
                                    <asp:HyperLink ID="tagLink" runat="server"></asp:HyperLink>
                                </ItemTemplate>
                            </asp:Repeater>
                        </td>
                        <td id="DownloadLinkWrap" runat="server"><asp:HyperLink ID="FileDownloadLink" runat="server" Text="<%$Resources:Items_Download %>" /></td>
                    </tr>
            </ItemTemplate>
            <FooterTemplate>
                </tbody>
                </table>
            </FooterTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>
<telerik:Pager ID="pager1" runat="server">
    <LayoutTemplate>
         <asp:Repeater ID="PageRepeaterLinkButton" runat="server">
            <HeaderTemplate>
                <ol class="sf_pager">
                <li><asp:LinkButton ID="PreviousPage" runat="server" Text="<%$Resources:Items_PreviousPage %>"></asp:LinkButton></li>
            </HeaderTemplate>
            <ItemTemplate>
                <li>
                    <asp:LinkButton ID="SingleItem" runat="server" />
                </li>
            </ItemTemplate>
            <FooterTemplate>
                <li><asp:LinkButton ID="NextPage" runat="server" Text="<%$Resources:Items_NextPage %>"></asp:LinkButton></li>
                </ol>
            </FooterTemplate>
        </asp:Repeater>
        <asp:Repeater ID="PageRepeaterHyperLink" runat="server">
            <HeaderTemplate>
                <ol class="sf_pager">
                <li><asp:HyperLink ID="PreviousPage" runat="server" Text="<%$Resources:Items_PreviousPage %>"></asp:HyperLink></li>
            </HeaderTemplate>
            <ItemTemplate>
                <li>
                    <asp:HyperLink ID="SingleItem" runat="server" />
                </li>
            </ItemTemplate>
            <FooterTemplate>
                <li><asp:HyperLink ID="NextPage" runat="server" Text="<%$Resources:Items_NextPage %>"></asp:HyperLink></li>
                </ol>
            </FooterTemplate>
        </asp:Repeater>
    </LayoutTemplate>
</telerik:Pager>

Finally all you have to do is add the control to your Sitefinity toolbox.

You can download the control source code, markup for template, style sheet and localization resources file from this link: CustomDownloadList

4 comments

Leave a comment
  1. KingKong Feb 18, 2010
    Thanks Rado. That's cool.
  2. Muneeb Feb 18, 2010
    Thanks for the tip.
    I have one query, (may be repeating): I already have my audio lectures uploaded to my website. I want to create a library that points out to the items already uploaded. 
    Is there a way to do so?
    Thanking you in anticipation.
  3. Romi Feb 19, 2010
    Thanks Rado,
    Veny nice and usefull
    Could you help us how to add a icon in place of extension and one counter for downloads.
  4. Radoslav Georgiev Feb 22, 2010
    @Muneeb, this is not possible through the UI with out of the box functionality. You should create libraries in the Images and Documents module and upload files in the libraries not to file system.

    @Romi, for the icons for extensions you have to change the markup and code file little bit. Instead of having a literal to display the extension here:
    <td id="ExtWrap" runat="server"><asp:Literal id="Extension" runat="server"></asp:Literal></td>

    You should put an asp:Image for example. Then you should modify the ItemsRepeater_DataBound event handler. Instead of finding a Literal with ID extension it should find the image control. Once you get the extension from the metadata you should give the image control a path. Should be something like this:
    string extension = contentItem.GetMetaData("Extension") as string;
    //remove "." symbol from the string
    extension = extension.Substring(1);
    ExtensionIcon.ImageUrl = string.Concat("~/Images/Icons/", extension, ".png");

    You can take a look at this forum post to see how to implement counters: Count for download

    Leave a comment