This post shows how to create simple filter webpart, that will filter xsltlistview webpart based on user input or server logic. The trick here is to change view query dynamically. Once you added webpart to the page, it will find xsltlistview webpart on the same page and will add caml query to the original query to make it work like a filter. This technique can be applied in several cases e.g. to implement a kind of seach or hide items from listview based on user role etc.
In this example I will show how create simple search on field web part.
First, create new Visual WebPart project, and add simple markup. In my example it will be dropdownlist for filter field selection, textbox for filter value and button to apply query.
<table>
<tr>
<td>Field:</td>
<td><asp:DropDownList ID="FilterField" runat="server"/></td>
<td>Value:</td>
<td><asp:TextBox ID="FilterValue" runat="server" Width="200px"/></td>
<td><asp:Button ID="ButtonOK" Text="OK" runat="server" Width="100px" UseSubmitBehavior="false"/></td>
</tr>
</table>
Note UseSubmitBehavior=”false” for the button – I will explain it later.
Now let’s write code to make it work – open code behind file and add code to find xsltlistview webpart and populate dropdownlist with view fields to CreateChildControls:
private SP.XsltListViewWebPart _listview;
This code is quite simple – just iterates through all page controls and looks for XsltListViewWebPart type. Once webpart is found we can get its list and view to find out view fields – this fields are available for query.
All we need to do now is to change XmlDefinition property of XsltListViewWebPart, but this is not so simple because you need to do that in OnLoad event (if do it after that it will not work), so control values will not reflect user input at this stage. So you cannot just use FilterValue.Text to get filter value. The workaround is to read user input from request parameters. Let’s write code for translating user input into CAML query (I will use simple “contains” filtering logic):
protected string Query
{
get
{
string res = string.Empty;
string filterField = Page.Request.Params[FilterField.UniqueID];
string filterValue = Page.Request.Params[FilterValue.UniqueID];
if (!string.IsNullOrEmpty(filterField) && !string.IsNullOrEmpty(filterValue))
{
res = string.Format("{1}",
filterField, filterValue);
}
return res;
}
}
Note, how I get filter field and filter value from Page.Request.Params. The same thing is with search button – you cannot just add event handler for the button, because it will occur after OnLoad and that’s too late to change query. To find out if search button was clicked at OnLoad stage you need to set UseSubmitBehavior=”false” for the button and check __EVENTTARGET param – if button was clicked, then __EVENTTARGET will contain unique ID of the button. Once the click occured, remember it is ViewState. The code is following:
//property for storing search flag in viewstate
protected bool ApplySearch
{
get { return ViewState["ApplySearch"] != null ? (bool)ViewState["ApplySearch"] : false; }
set { ViewState["ApplySearch"] = value; }
}
…..
Now we’re ready to change xml of XsltListView webpart to filter list. There number of ways to do that, but I will use XmlDocument:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//check if postback is caused by Search button
if (Page.Request.Params["__EVENTTARGET"] == ButtonOK.UniqueID)
{
ApplySearch = true;
}
_listview = FindListViewWebPart(Page);
if (ApplySearch && (_listview != null))
{
if (!string.IsNullOrEmpty(Query))
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(_listview.XmlDefinition);
XmlElement viewXml = xml["View"];
XmlNode viewQuery = viewXml.SelectSingleNode("//Query");
XmlNode where = viewQuery.SelectSingleNode("//Where");
if (where == null)
{
where = xml.CreateElement("Where");
viewQuery.AppendChild(where);
}
if (where.ChildNodes.Count == 1)
{
where.InnerXml = string.Format("{0}{1}", where.FirstChild.OuterXml, Query);
}
else
{
where.InnerXml = Query;
}
_listview.XmlDefinition = xml.InnerXml;
}
else
{
ApplySearch = false;
}
}
}
And that’s all – test your web part! The complete project for Visual Studio 2010 can be downloaded here.

Thanks for the great solution.
One thing I noticed is that the column filtering does not work 100%. In the list you do not get the filtered items only according to the custom query. You get the items in the whole list.
Any ideas how to adjust the filtering column popup?
Charles
mifsudcharles@gmail.com
Charles, thanks for feedback! The column filtering popup receives filter values using async server request, so I guess somehow it “skips” the custom query. I did not pay attention to this scenario, when wrote the post. I'll investigate the problem and let you know about the results.
Charles, unfortunately, I did not find solution on this. The problem is that SharePoint 2010 filtering popup send async request not to listview webpart (as it was in SharePoint 2007) but to another page (/_layouts/filter.aspx). The request contains list id, view id and column number, so response contains all column values from original view and dynamic changes to view definition in xsltlistview webpart do not affect this. on SharePoint 2010. Filtering XsltListViewWebPart using caml query
Hey Ivan,
Thanks for the great solution.Can I have the VS2010 solution to download as the filterwebpart.rar seem to be corrupt.
Thanks in advance
Hi! I looks like archive file was corrupted. I've just updated the link, so try again and let me know if you have any problems with that.
why does xml.LoadXml(webPart.XmlDefinition);
returns an error : Root element is missing.
and the xmldefinition is empty???
Hi!
The error comes because xmldefinition is empty, and it is empty, because it was not properly initialized. Are ViewId and ListId set for the webpart? If not, then I guess it is expected behavior.
Hi,
Nice one. This is what i was looking for a long time..i have a caml query. Could you tell me how to insert this in the code. The caml is generated by U2U caml builder.
DocFileB
Thanks
Hi! To insert predefined CAML query, you need to override Query property in the code above as following:
protected string Query
{
get { return [inner xml string of your ];}
}