SharePoint Filter Web Part
SharePoint includes a couple of useful web parts that can be used to filter other web parts. The problem is, they are only available in the Enterprise edition. It is easy, however, to build our own filters.
The key interface here is ITransformableFilterValues; it defines the contract for passing one or more values into another web part for the purpose of filtering it. Another useful interface is IDefaultFilterValue, which, guess what, defines a default value to be returned in case no one exists to be returned. Let's see an example that retrieves values from the query string:
public class QueryStringFilter : WebPart, ITransformableFilterValues, IDefaultFilterValue
{
public QueryStringFilter()
{
this.ChromeType = PartChromeType.None;
this.Hidden = true;
this.MultiValueHandling = MultiValueHandling.First;
this.MultiValueSeparator = String.Empty;
}
[WebDisplayName("Default Value")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Default Value")]
[DefaultValue("")]
[Description("")]
[Personalizable(PersonalizationScope.Shared)]
public String DefaultValue { get; set; }
[WebDisplayName("Allow All Value")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Allow All Value")]
[Personalizable(PersonalizationScope.Shared)]
[DefaultValue(false)]
[Description("")]
public Boolean AllowAllValue { get; set; }
[WebDisplayName("Allow Empty Value")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Allow Empty Value")]
[Personalizable(PersonalizationScope.Shared)]
[DefaultValue(false)]
[Description("")]
public Boolean AllowEmptyValue { get; set; }
[WebDisplayName("Allow Multiple Values")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Allow Multiple Values")]
[Personalizable(PersonalizationScope.Shared)]
[DefaultValue(false)]
[Description("")]
public Boolean AllowMultipleValues { get; set; }
[WebDisplayName("Query String Parameter Name")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Query String Parameter Name")]
[Personalizable(PersonalizationScope.Shared)]
[DefaultValue("")]
[Description("")]
public String ParameterName { get; set; }
[WebDisplayName("Multi Value Handling")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Multi Value Handling")]
[Personalizable(PersonalizationScope.Shared)]
[DefaultValue(MultiValueHandling.First)]
[Description("")]
public MultiValueHandling MultiValueHandling { get; set; }
[WebDisplayName("Multi Value Separator")]
[WebPartStorage(Storage.Shared)]
[WebBrowsable(true)]
[FriendlyName("Multi Value Separator")]
[Personalizable(PersonalizationScope.Shared)]
[DefaultValue("")]
[Description("")]
public String MultiValueSeparator { get; set; }
ReadOnlyCollection<String> ITransformableFilterValues.ParameterValues
{
get
{
var list = new List<String>();
if (String.IsNullOrWhiteSpace(this.ParameterName) == false)
{
if (this.AllowMultipleValues == false)
{
list.Add(this.Context.Request.QueryString[this.ParameterName]);
}
else
{
var index =
Array.IndexOf(
this.Context.Request.QueryString.AllKeys.Select(x => (x ?? String.Empty).ToLowerInvariant()).ToArray(),
this.ParameterName.ToLowerInvariant());
if (index >= 0)
{
if (this.MultiValueHandling == MultiValueHandling.First)
{
list.Add(this.Context.Request.QueryString.GetValues(index).First());
}
else if (this.MultiValueHandling == MultiValueHandling.All)
{
list.AddRange(this.Context.Request.QueryString.GetValues(index));
}
else
{
list.Add(String.Join(this.MultiValueSeparator, this.Context.Request.QueryString.GetValues(index)));
}
}
}
if (list.Count == 0)
{
if (String.IsNullOrWhiteSpace(this.DefaultValue) == false)
{
list.Add(this.DefaultValue);
}
else
{
if (this.AllowAllValue == false)
{
if (this.AllowEmptyValue == true)
{
list.Add(String.Empty);
}
}
else
{
list.Add(null);
}
}
}
}
return new ReadOnlyCollection<String>(list);
}
}
[ConnectionProvider("Query String Filter", "ITransformableFilterValues", AllowsMultipleConnections = true)]
public ITransformableFilterValues GetFilterValues()
{
return this;
}
}
There are a couple of public properties:
-
ParameterName: the query string key whose value is to be returned;
-
DefaultValue: the default value to be returned, in case the query string does not contain a value for the ParameterName key;
-
AllowAllValue: whether to allow the all (null) value;
-
AllowEmptyValue: whether to allow the empty ("") value;
-
AllowMultipleValues: whether to allow multiple values or not;
-
MultiValueHandling: what to do if multiple values are found for the ParameterName key: select the first only, return all or combine them all into one;
-
MultiValueSeparator: the separator for combining multiple values.
The web part is invisible and will only show the chrome when the page is in edit mode. After you add it to a page, you can add a connection of type filter to another web part and select the field on the other web part that you want to filter by. The actual
ITransformableFilterValues implementation is returned by the GetFilterValues method, which is marked with the ASP.NET ConnectionProvider attribute so as to make it a connection provider, and can feed several other web parts. The logic inside ParameterValues is a bit tricky because of the AllowAllValue and AllowEmptyValue properties but I think you'll have no problems following it.
You would normally apply a filter using the browser interface, but you can also do it in markup:
<WebPartPages:SPProxyWebPartManager runat="server">
<SPWebPartConnections>
<WebPartPages:SPWebPartConnection ConsumerConnectionPointID="DFWP Filter Consumer ID" ConsumerID="listViewWebPart" ProviderConnectionPointID="ITransformableFilterValues" ProviderID="queryStringFilterWebPart">
<WebPartPages:TransformableFilterValuesToParametersTransformer ConsumerFieldNames="LinkTitle" ProviderFieldNames="TaskName"/>
</WebPartPages:SPWebPartConnection>
</SPWebPartConnections>
</WebPartPages:SPProxyWebPartManager>
In this example, I am binding the LinkTitle field of a list view web part to the TaskName query string parameter provided by the QueryStringFilter web part. If the query string contains a TaskName parameter that matches the list view's LinkTitle, it will show these records.