Thursday, September 11, 2014

Add Excel type Filtering to Repeater or Gridview in ASP.NET

In this example we will add dropdown list filter to repeater. The filters will be created dynamically at runtime.

1) Create a repeater control
<asp:Repeater runat="server" ID="rptData" OnItemCreated="rptData_ItemCreated" EnableViewState="false">
        <HeaderTemplate>
            <table>
                <tr>
                    <td>Department</td>
                    <td>Name</td>
                    <td>Age</td>
                </tr>
                <tr>
                    <td id="Department" runat="server" ></td>
                    <td id="Name" runat="server" ></td>
                    <td id="Age" runat="server"></td>
                </tr>
        </HeaderTemplate>
        <ItemTemplate>
            <tr>
                <td><%# Eval("Department") %></td>
                <td><%# Eval("Name") %></td>
                <td><%# Eval("Age") %></td>
            </tr>
        </ItemTemplate>
        <FooterTemplate>
            </table>
        </FooterTemplate>
    </asp:Repeater>

2) Create an Employee class
[Serializable]
        public class Employee
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public string Department { get; set; }
            public Employee() { }

            public static List<Employee> GetEmployees()
            {
                List<Employee> employees = new List<Employee>();
                employees.Add(new Employee() { Name = "Victor", Age = 31, Department = "Finance" });
                employees.Add(new Employee() { Name = "Jeff", Age = 35, Department = "Finance" });
                employees.Add(new Employee() { Name = "Tom", Age = 42, Department = "IT" });
                employees.Add(new Employee() { Name = "Matt", Age = 42, Department = "IT" });
                return employees;
            }
        }
3) On page load bind data to the repeater
protected void Page_Load(object sender, EventArgs e)
        {
            rptData.DataSource = Employee.GetEmployees();
            rptData.DataBind();
        }

OK now we will start the code to add filtering to the repeater.

4) Add “ItemCreated” Event
protected void rptData_ItemCreated(object sender, RepeaterItemEventArgs e)
        {
            //Check if item is header
            if (e.Item.ItemType == ListItemType.Header)
            {
                //Get employee data
                List<Employee> tempData = ViewState["filtered_data"] == null?Employee.GetEmployees():(List<Employee>)ViewState["filtered_data"] ;
                //Get properties of employee data. We will be adding drop down list filters for these properties
                foreach (PropertyInfo propertyInfo in typeof(Employee).GetProperties())
                {
                    if (e.Item.FindControl(propertyInfo.Name) != null)
                    {
                        //Create dropdownlist
                        DropDownList ddltemp = new DropDownList();
                        ddltemp.Items.Add(new ListItem("Select", string.Empty));

                        //Get value of the selected property from the list
                        foreach (string value in (from x in tempData select propertyInfo.GetValue(x, null).ToString()).Distinct().ToList())
                        {
                            ddltemp.Items.Add(new ListItem(value, value));
                        }
                        ddltemp.Attributes.Add("style", "width:70px;");
                        ddltemp.ID = "ddl" + propertyInfo.Name;
                        //Set autopost back
                        ddltemp.AutoPostBack = true;
                        //Add event handler
                        ddltemp.SelectedIndexChanged += new EventHandler(ddlTemp_SelectedIndexChanged);
                        //Add dropdownlist to the repeater header
                        e.Item.FindControl(propertyInfo.Name).Controls.Add(ddltemp);
                    }
                }
            }
        }

5) Add dropdownlist post back event to filter data

  protected void ddlTemp_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Get dropdownlist object that send the request
            DropDownList ddlTemp = (DropDownList)sender;
            List<Employee> tempData = ViewState["filtered_data"] == null ? Employee.GetEmployees() : (List<Employee>)ViewState["filtered_data"];

            //Filter the list based on the selected value of the property
            List<Employee> temp = (from x in tempData
                                           where x.GetType().GetProperties().Where(y => y.Name == ddlTemp.ID.Replace("ddl", "")
                                                                                                   && y.GetValue(x, null).ToString() == ddlTemp.SelectedItem.Text).Count() > 0
                                           select x).ToList();

            ViewState["filtered_data"] = temp;
            rptData.DataSource = temp;
            rptData.DataBind();
        }

That’s it! Run the application and you can filter records from header of the repeater!