This will extend the default filters that Dynamic Data provides by adding a free text search box the will search multiple text fields on the same page. I have done this in a few projects now as one off but after this post Custom filters & searches within DD in Visual Web Developer 2010 on the Dynamic Data Forum I decided to document it here.
Figure 1 – Multi Column Search
Here in Figure 1 you can see the multi column search box, in this example the search is on FistName, LastName, Address, City and Country, it will even allow search across entities e.g. on Orders Employee.LastName etc. which make it very flexible.
Things we will need to do
- Attribute to tell the system which columns to search on.
- Add mark-up to show the UI on the List page.
- Code to wire up the UI and QueryExtender.
The Attribute
This attribute will be added to the Class/Table not it’s columns and will have only one property Columns.
[AttributeUsage(AttributeTargets.Class)]
public class MultiColumnSearchAttribute : Attribute
{
public String[] Columns { get; private set; }
public MultiColumnSearchAttribute(params String[] columns)
{
Columns = columns;
}
}
Listing 1 – MultiColumnSearchAttribute
and we apply it as in Listing 2 The Employee table show standard multi-column search but the Order table shows how we can search across entity boundaries you can see this in Figure 2.
[MetadataTypeAttribute(typeof(Employee.EmployeeMetadata))]
[MultiColumnSearch(
"LastName",
"FirstName",
"Address",
"City",
"Country")]
public partial class Employee
{
internal sealed class EmployeeMetadata
{
//...
}
}
[MetadataTypeAttribute(typeof(Order.OrderMetadata))]
[MultiColumnSearch(
"Employee.LastName",
"Employee.FirstName",
"Customer.CompanyName",
"Customer.ContactName",
"Shipper.CompanyName")]
public partial class Order
{
internal sealed class OrderMetadata
{
//...
}
}
Listing 2 – sample metadata
Figure 2 – cross entity search
Adding UI Mark-Up
I have added the multi column search UI in between the validators and the QueryableFilterRepeater see Listing 3
<asp:DynamicValidator runat="server" ID="GridViewValidator" ControlToValidate="GridView1"
Display="None" CssClass="DDValidator" />
<fieldset id="MultiSearchFieldSet" class="DD" runat="server" visible="false">
<legend>Full Text Search</legend>
<asp:TextBox ID="txbMultiColumnSearch" CssClass="DDTextBox" runat="server" />
<asp:Button ID="btnMultiColumnSearchSubmit" CssClass="DDControl" runat="server" Text="Search"
OnClick="btnMultiColumnSearch_Click" />
<asp:Button ID="btnMultiColumnSearchClear" CssClass="DDControl" runat="server" Text="Clear"
OnClick="btnMultiColumnSearch_Click" />
</fieldset>
<br />
<asp:QueryableFilterRepeater runat="server" ID="FilterRepeater">
Listing 3 – Multi Column Search UI
Code to wire up the UI and QueryExtender
/// <summary>
/// Setups the multi column search.
/// </summary>
private void SetupMultiColumnSearch()
{
// get multi column search attribute
var multiColumnSearch = table.GetAttribute<MultiColumnSearchAttribute>();
if (multiColumnSearch != null)
{
var searchExpression = new SearchExpression()
{
DataFields = multiColumnSearch.Columns.ToCsvString(),
SearchType = SearchType.Contains
};
// create control parameter
var controlParameter = new ControlParameter() { ControlID = txbMultiColumnSearch.ID };
// add control parameter to search expression
searchExpression.Parameters.Add(controlParameter);
// set context
searchExpression.SetContext(GridQueryExtender, Context, GridDataSource);
// add search expression to query extender
GridQueryExtender.Expressions.Add(searchExpression);
// make multicolumn search field set visible
MultiSearchFieldSet.Visible = true;
}
}
Listing 5 – SetupMultiColumnSearch method
In Listing 5 (which is called from the Page_Init method) we get the attribute and the SearchExpression the if both are not null we add the fields to the SearchExpressions DataFileds property, then we make the whole thing visible.
Note: Much thanks to
David Ebbo who sorted out the issue I had had with adding the search expression in code rather than declaratively.
protected void btnMultiColumnSearch_Click(object sender, EventArgs e)
{
var button = (Button)sender;
if (button.ID == btnMultiColumnSearchClear.ID)
txbMultiColumnSearch.Text = String.Empty;
}
Listing 6 – button event
And lastly we need an event to fire when the clear button is fired.
Note: I have both buttons wired-up to this handler as I also add session history here so that when you search on something and go to another page when you return you get the same search, but I also want it cleared if I click the clear button.
Download