Tweaking the Filter Repeater

The default implementation of Dynamic Data provides a drop down list box for each foreign key and boolean field in a table. The drop down list allows you to filter the table with the value selected from the drop down list box. The figure below shows a view of the Product table from the AdventureWorksLT database. Several columns are not displayed because the scaffoldcolumnattribute was applied.

The figure below shows the Product table again after Mountain Bikes is selected in the ProductCategory drop down list. Only products with product category Mountain Bikes are displayed.

The drop down list box is implemented in Dynamic Data by the FilterUserControl.ascx user control in the DynamicData\Content folder. While the filter user control is useful to filter a table when there are a relatively few foreign keys used as categories, it can be unmanageable on tables with hundreds or more foreign keys. For example, the CustomerAddress table of the AdventureWorksLT database has over 400 AddressID foreign keys, and each foreign key points to only one address of a customer (either the Main Office or the Shipping address).

When the foreign key field displayed by the filter user control is a very long string, the drop down list box can move off the browser window. This document will offer and approach to limit the width of the drop down list box. The figure below shows the ProductModelProductDescriptions from the AdventureWorksLT database.

In this blog I show how I like to establish a maximum number of entries in the filter repeater and how to set the maximum width.

Modifying the filter user control to limit number of entries

Editing the filter user control

1. Add a key element to the appSettings Element in the web.config file that will set an upper bound to the number of foreign key entries that will be displayed. The following example sets the upper bound to 55. 

 <appSettings>
  <add key="FilterUC_FK_limit" value="955"/>
  <add key="FilterUC_Char_limit" value="50"/>
</appSettings>

1 Add a text label to the the filter user control in the FilterUserControl.ascx file found in the DynamicData\Content folder. The following example shows the completed markup.

 <%@ Control Language="C#" CodeFile="FilterUserControl.ascx.cs" Inherits="FilterUserControl" %>

<asp:Label ID="LBL1" runat="server" Text="Label" ForeColor= "Brown" Font-Bold="true" />
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" EnableViewState="true" CssClass="droplist">
    <asp:ListItem Text="All" Value="" />
</asp:DropDownList>

3. Add a string property to the FilterUserControl. For example, add a property with the name LBL_Txt that will be used to set the label we added to the FilterUserControl.aspx file in a previous step.

4. Add the Page_PreRender method in the FilterUserControl code behind file and set the label text. For example, set the label text with the LBL_Txt property created in the previous step.

5. Modify the Page_Init method in the FilterUserControl code behind file to limit the number of foreign keys displayed. The FilterUC_FK_limit application setting created in the first step will be used to set the maximum number of entries in the drop down list box. The following example shows the completed FilterUserControl code behind file.

Visual Basic

 Imports System.Web.DynamicData

Partial Class FilterUserControl
    Inherits System.Web.DynamicData.FilterUserControlBase
    '
    Public LBL_Txt As String
    '
    Public Overrides ReadOnly Property SelectedValue As String
        Get
            Return DropDownList1.SelectedValue
        End Get
    End Property
    '
    Public Event SelectedIndexChanged As EventHandler
    '
    Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
        '
        If Page.IsPostBack Then
            Return
        End If
        '
        PopulateListControl(DropDownList1)
        '
        Dim maxCnt As Integer = Convert.ToInt32(ConfigurationManager.AppSettings("FilterUC_FK_limit"))
        If (DropDownList1.Items.Count > maxCnt) Then
            DropDownList1.Visible = False
            LBL1.Visible = False
        End If
        '
        If Not String.IsNullOrEmpty(InitialValue) Then
            DropDownList1.SelectedValue = InitialValue
        End If
        '
    End Sub
    '
    '
    Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
        LBL1.Text = LBL_Txt
    End Sub
End Class

C#

 using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;

public partial class FilterUserControl : System.Web.DynamicData.FilterUserControlBase {

    public string LBL_Txt { get; set; }

    public event EventHandler SelectedIndexChanged {
        add {
            DropDownList1.SelectedIndexChanged += value;
        }
        remove {
            DropDownList1.SelectedIndexChanged -= value;
        }
    }

    public override string SelectedValue {
        get {
            return DropDownList1.SelectedValue;
        }
    }

    protected void Page_PreRender(object sender, EventArgs e) {
        LBL1.Text = LBL_Txt;
    }

    protected void Page_Init(object sender, EventArgs e) {

        if (Page.IsPostBack)
            return; PopulateListControl(DropDownList1);

        int maxCnt = Convert.ToInt32(ConfigurationManager.AppSettings["FilterUC_FK_limit"]); 
        if (DropDownList1.Items.Count > maxCnt) {
            DropDownList1.Visible = false;
            LBL1.Visible = false;
        }

        if (!String.IsNullOrEmpty(InitialValue))
            DropDownList1.SelectedValue = InitialValue;
    }
}

 

5. Remove the original filter label from the page template (list.aspx and listDetails.aspx) and initialize the new label. The original markup is shown below.

 <asp:FilterRepeater ID="FilterRepeater" runat="server">
    <ItemTemplate>
       <asp:Label runat="server" Text='<%# Eval("DisplayName") %>' AssociatedControlID="DynamicFilter$DropDownList1" />
        <asp:DynamicFilter runat="server" ID="DynamicFilter" OnSelectedIndexChanged="OnFilterSelectedIndexChanged" />
     </ItemTemplate>
     <FooterTemplate><br /><br /></FooterTemplate>
 </asp:FilterRepeater>

The replacement markup is shown below.

 <ItemTemplate>
    <asp:DynamicFilter runat="server" ID="DynamicFilter" LBL_Txt='<%# Eval("DisplayName") %>'
                      OnSelectedIndexChanged="OnFilterSelectedIndexChanged" />
  </ItemTemplate>

 

Part II:  Limiting the width of the filter user control Part II:

To limit the width of the drop down list box, the elements of the list box will be truncated at the maximum allowed character width.Editing the filter user control for maximum characters1. Add a key element to the appSettings Element in the web.config file that will set an upper bound on the number of characters that will be copied to each element of the drop downn list. The key with value FilterUC_Char_limit sets the maximum number of characters to 50.

 <appSettings>
  <add key="FilterUC_FK_limit" value="955"/>
  <add key="FilterUC_Char_limit" value="50"/>
</appSettings>

2. Modify the Page_Init method in the FilterUserControl code behind file to limit the number of characters to be copied to the drop down list box. The following example shows how to limit the number of characters.

C#

 int maxLen = Convert.ToInt32(ConfigurationManager.AppSettings["FilterUC_Char_limit"]);

for (int i = 0; i < DropDownList1.Items.Count; i++) {
   string s = DropDownList1.Items[i].Text;

   if (s.Length > maxLen) {
      s = s.Substring(0, maxLen - 1);
      s += " ... (see Details for full)";
      DropDownList1.Items[i].Text = s;
   }
}

Visual Basic

 Dim maxLen As Integer = Convert.ToInt32(ConfigurationManager.AppSettings("FilterUC_Char_limit"))
   For i As Integer = 0 To DropDownList1.Items.Count - 1

       Dim s As String = DropDownList1.Items(i).Text

       If s.Length > maxLen Then
           s = s.Substring(0, maxLen - 1)
           s += " ... (see Details for full)"
           DropDownList1.Items(i).Text = s
       End If
   Next

The figure below shows the results with the ProductModelProductDescription table.