More in this section
Blogs RSS feed

Filtering Sitefinity ContentView-based Controls on the Frontend

by Boyan Barnev
Sitefinity's ContentView class, and all its inheritors (News, Blog Posts, Events, etc. widgets) are among the most popular subjects discussed in our blog post. And there's a pretty good reason for that, after all - our ContentView widgets are one of the most important elements that build the Sitefinity experience - they help you select the data you want to display and its behavior on the frontend.

Keeping in mind the numerous use case scenarios ContentView controls cover, you'd be surprised at how much they can do in addition if you plug in the right places and implement your own business logic.

Today we're going to demonstrate how one can inherit from a ContentView widget and directly manipulate its DataSource in order to achieve frontend filtering.

Let's take News for example.  As every other ContentView widget the NewsView widget also has a Master and Details view. Since we want to filter the list of items, we'll need to modify its List of news template and inherit from its MasterView class.

1. You need to create a new UserControl based on the default News widget list template.
In this new template you can define the controls that will handle the presentational part of your filtering mechanism. For example a TextBox/DropDownList that you will populate with the filter options, and a Button that will execute the filtering. For example:
<%@ Control Language="C#" %>
<%@ 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="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %>
<telerik:RadComboBox runat="server" ID="categoriesCombo" Skin="Sitefinity" />
<asp:Button runat="server" ID="filterBtn" Text="Filter" />
<telerik:RadListView ID="NewsList" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false">
        <sf:ContentBrowseAndEditToolbar ID="MainBrowseAndEditToolbar" runat="server" Mode="Add"></sf:ContentBrowseAndEditToolbar>
        <ul class="sfnewsList sfnewsListTitleDateSummary">
            <asp:PlaceHolder ID="ItemsContainer" runat="server" />
        <li class="sfnewsListItem">
            <h2 class="sfnewsTitle">
                <sf:DetailsViewHyperLink ID="DetailsViewHyperLink1" TextDataField="Title" ToolTipDataField="Description" runat="server" />
            <div class="sfnewsMetaInfo">
                <sf:FieldListView ID="PublicationDate" runat="server" Format="{PublicationDate.ToLocal():MMM dd, yyyy}" />
            <sf:FieldListView ID="summary" runat="server" Text="{0}" Properties="Summary" WrapperTagName="div" WrapperTagCssClass="sfnewsSummary" />
            <sf:DetailsViewHyperLink ID="FullStory" Text="<%$ Resources:NewsResources, FullStory %>" runat="server" CssClass="sfnewsFullStory" />
            <sf:ContentBrowseAndEditToolbar ID="BrowseAndEditToolbar" runat="server" Mode="Edit,Delete,Unpublish"></sf:ContentBrowseAndEditToolbar>
<sf:Pager ID="pager" runat="server"></sf:Pager>
<asp:PlaceHolder ID="socialOptionsContainer" runat="server" />

2. Once we've created the custom template we need to inherit from the default Telerik.Sitefinity.Modules.News.Web.UI.MasterListView class.
In the new class we can override MasterListView's LayoutTemplatePath property and point it to the custom template we have already created:
public override string LayoutTemplatePath
               return this.layoutTemplatePath;
               base.LayoutTemplatePath = value;
private string layoutTemplatePath = "~/CustomWidgets/News/Views/NewsMasterListViewCustomTemplate.ascx";

3. Next,  you can then get a reference to your controls so you can operate with them:
public virtual RadComboBox CategoriesCombo
               return this.Container.GetControl<RadComboBox>("categoriesCombo", false);
       public virtual Button FilterButton
               return this.Container.GetControl<Button>("filterBtn", false);

4. We can then override the InitializeControls method of the MasterListView, and implement our business logic for populating the filter options.
A common use case scenario we encounter in support is the need to have a categories dropdown, that would allow filtering the list dynamically, so let's go with this one.
In order to ensure we're listing only categories that have been used to mark items of this content type we can query the TaxonomyStatistics - this is where Sitefinity keeps a reference for each taxon about the number of marked items, and their content type. So we can do something like:
protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container, Telerik.Sitefinity.Web.UI.ContentUI.Contracts.IContentViewDefinition definition)
           var dataItemType = "Telerik.Sitefinity.News.Model.NewsItem";
           //Get all taxa that have been used for the particular dataItemType
           TaxonomyManager taxonomyManager = TaxonomyManager.GetManager();
           var newsCategories = taxonomyManager.GetStatistics()
                                   .Where(tS => tS.DataItemType == dataItemType && tS.TaxonomyId == TaxonomyManager.CategoriesTaxonomyId)
                                   .Where(tS => tS.StatisticType == ContentLifecycleStatus.Live && tS.MarkedItemsCount > 0)
                                   .Select(t => new
                                       taxonId = t.TaxonId,
                                       taxonTitle = taxonomyManager.GetTaxon<HierarchicalTaxon>(t.TaxonId).GetString("Title"),

5. Once we have the datasource ready, we need to bind it to our dropdown:
//bind the RadComboBox to the taxa
            this.CategoriesCombo.DataTextField = "taxonTitle";
            this.CategoriesCombo.DataValueField = "taxonId";
            this.CategoriesCombo.DataSource = newsCategories;
            //Add a default EmptyItem
            RadComboBoxItem emptyItem = new RadComboBoxItem("Choose category");
            this.CategoriesCombo.Items.Insert(0, emptyItem);

Up to this point we have everything we need to display a list of taxa in a dropdown on the list of news items. Our next steps will define our filtering logic.
In order to achieve the best performance we would recommend modifying the default FilterExpression dynamically. The FilterExpression in Sitefinity ContentView widgets is used when constructing the query to the database when we retrieve the data source. This means that by modifying it before the query gets executed, this will ensure we're not making any additional calls to the database, but rather just affecting how the query is constructed, and what items we retrieve from the database.

In order to modify the FilterExpression, and for this modification to take effect we need to do two things:

6. Override the GetItemsList() method - this is where we construct the query and get the items. So we can simply get the selected value from our categories dropdown and apply this value to the filter expression:

protected override IQueryable<Telerik.Sitefinity.News.Model.NewsItem> GetItemsList(ref int? totalCount)
            //check if a category to filter by is selected and add it to the filter expression
            if (this.CategoriesCombo.SelectedIndex > 0)
                this.FilterExpression += string.Format(" AND Category.Contains(({0}))", this.CategoriesCombo.SelectedValue.ToString());
            //populate items list
            return base.GetItemsList(ref totalCount);

7. Due to the specific lifecycle of the ContentView widgets we will need to override the 
OnPreRender() method - this is where we're going to invoke the GetItemsList() and InitializeListView() methods of the ContentView, so we can ensure our filtering takes effect:
protected override void OnPreRender(EventArgs e)
           int? totalCount = 0;
           IQueryable<NewsItem> query = this.GetItemsList(ref totalCount);
           this.InitializeListView(query, totalCount);

That's it - once you have compiled your project successfully there's one last piece to complete today's exercise - we need to tell Sitefinity to use our custom Master View instead of the default one.

To do that we can take advantage of the concept of Definitions in Sitefinity. They allow us to substitute any existing view with a custom one through the corresponding ContentViewDefinitionElement.
8. In the current case we just need to go to Administration->Settings->Advanced->ContentView->News->News Frontend -> Views-> NewsFrontendList and replace the ViewType property with the CLR type of our custom view. Save the changes and you-re done - from this point on all News widgets throughout your site will use the custom master view instead of the default one.

As usual, here's a sample video demonstrating this functionality.

The complete sample can be downloaded from here:

With this we finish today's blog post. Feel free to modify it as per your specific requirements, and we hope you found this information useful.


Leave a comment
  1. Jay Greasley Mar 24, 2014


     I use your code to build a widget but when I view the page with the widget on, I get:


    Object reference not set to an instance of an object.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.NullReferenceException: Object reference not set to an instance of an object.

    Source Error: 

    Line 95: }
    Line 96: //populate items list
    Line 97: return base.GetItemsList(ref totalCount);
    Line 98: }
    Line 99:


    Can you help at all?



  2. Jay Greasley Mar 24, 2014

    the error is on line 97

  3. Jay Greasley Mar 24, 2014

    Update - it was failing because I was trying to use it as a general widget, not as a replacement for the News MasterListView. My bad ;-)

  4. Jay Greasley Mar 25, 2014


     A follow up question though - how would I do the same for a custom module?



  5. James Applegate Sep 22, 2014


    Thanks for the code sample. I used your code it is showing up fine. Only issue is i dont know how to add the categories. Can you please let me know how to add categories in the drop down. 


    Leave a comment