Monday, November 23, 2009

SharePoint List Filter web part

In SharePoint 2007 Enterprise version, Microsoft provides lots of Filter web part. One of them is SharePoint List Filter web part. It uses a SharePoint list as data source. The problem of this filter is that it doesn’t display the items in the list in the page, user has to click the filter icon to launch another window and then select an item in the popup window. My users complain that there’re too many clicks and they can’t see the items on the page.

Well, users are always right. So my job is to create a similar web part.

As this web part will connect to other web parts to provide filter function, first of all, the web part should inherit from ITransformableFilterValues.
public class SharePointListFilterWebPart : Microsoft.SharePoint.WebPartPages.WebPart, ITransformableFilterValues

Then override CreateChildControls.
try
{
base.CreateChildControls();

_values = new System.Web.UI.WebControls.RadioButtonList();

//Get all items from the list and add to the radio button control;
//Listname is a property so when configure the webpart, user can assign the list.
SPWeb web = Microsoft.SharePoint.SPContext.Current.Web;
SPList list = web.Lists[ListName];
SPListItemCollection listItems = list.Items;

if(listItems.Count > 0)
{
foreach (SPListItem listItem in listItems)
{
_values.Items.Add(new ListItem(listItem[ColumnName].ToString()));
}

//Default select the first item
if (!Page.IsPostBack)
_values.Items[0].Selected = true;

//auto postback when the user select different item.
_values.AutoPostBack = true;
this.Controls.Add(_values);
}
else
{
this.Controls.Add(new LiteralControl("There are no items in the list"));
}
}
catch (Exception ex)
{
//Exception handle
}

Then implement members in ITransformableFilterValues
public bool AllowEmptyValue { get { return false; } }
public bool AllowAllValue { get { return true; } }
public bool AllowMultipleValues { get { return true; } }
public string ParameterName { get { return ColumnName; } }

Add the following code to define the connection and the values to transfor.
public System.Collections.ObjectModel.ReadOnlyCollection ParameterValues
{
get
{
bool selected = false;

System.Collections.Generic.List values = new System.Collections.Generic.List();
for (int i = 0; i < _values.Items.Count; i++)
{
if (_values.Items[i].Selected)
{
values.Add(_values.Items[i].Value);

//for radion button
selected = true;
break;
}
}

if (!selected)
values.Add(_values.Items[0].Value);

System.Collections.ObjectModel.ReadOnlyCollection result = new System.Collections.ObjectModel.ReadOnlyCollection(values);
return result;
}
}

[ConnectionProvider(
"List",
"UniqueIDForListConnection",
AllowsMultipleConnections = true)]
public Microsoft.SharePoint.WebPartPages.ITransformableFilterValues SetConnection()
{
return this;
}


This is just a piece of my code. It’s better to install WSP Builder for Visual Studio which can create web part template and build SharePoint solution (*.wsp) easily.

Add InfoPath fields to Notification Email

In one of my K2 project which is an InfoPath Integrated Workflow, the users would like to see some information in InfoPath form, such as Company Name, Region, Office and so on in the notification email, so they can easily figure out what this email is about.

Well, this is a very good suggestion. Unfortunately in Notification Email Design Wizard in K2 workspace, there’s no way to get XML fields in the InfoPath form. After some investigations, I found Data Fields show in the Notification Email Design wizard. So we can create Data Fields and assign values for these data fields from xml fields. It is pretty simply to do it. The following sample creates two data fields Office and AdminRegion. In the workflow, add a Default Server Event (code), add the following code:

// The xml string in K2
string xml = K2.ProcessInstance.XmlFields["XML root field name"].Value;
// Load xml string to a xml object
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);

XmlNamespaceManager nsgr = new XmlNamespaceManager(doc.NameTable);
nsgr.AddNamespace("my",doc.DocumentElement.GetNamespaceOfPrefix("my"));

//Get Office value
string office = doc.SelectSingleNode("//my:Office",nsgr).InnerText;

//Get AdminRegion value
string adminRegion = doc.SelectSingleNode("//my:AdminRegion", nsgr).InnerText;

K2.ProcessInstance.DataFields["Office"].Value = office;
K2.ProcessInstance.DataFields["AdminRegion"].Value = adminRegion;



Now we can use Office and AdminRegion which are populated from the form in Notification email.