I have moved to http://blogs.msdn.com/mahuja
From now on, all new posts will be posted on my "new" MSDN blog http://blogs.msdn.com/mahuja.
Please update your feeds.
The learnings on technologies I work upon ...
From now on, all new posts will be posted on my "new" MSDN blog http://blogs.msdn.com/mahuja.
Please update your feeds.
Posted by Madhur at 5:50 PM 6 comments
To give some background for beginners, whenever we click Edit Page on Site Actions menu,
the pages switches into a different display mode called Design Mode. Its not a feature of
Sharepoint, but ASP.NET 2.0 Webparts Framework.
WebPartManager
control provides a programmatic interface, making it possible to switch the Web Part Page between browse, design, and edit display modes.For example, to programmatically switch the current page into design mode, you can simply add a link control with an event handler that sets the DisplayMode
property to DesignDisplayMode
.
Although this would work technically, but it would not give up the visible changes to page, like visibilty of Page Editing toolbar, webpart zones etc.
WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode;
This visual magic is done by lot of Javascript which is executed when we click Edit Page on Site Actions menu.
To build this link control, we need to figure out the javascript code which causes this behaviour.
This would be present in default.master. If we open Site Actions menu and do the View Source on IE.
Here is the code of our interest :
<td class="ms-siteactionsmenu" id="siteactiontd">
<span><a href="javascript:MSOLayout_ToggleLayoutMode();">Edit Page</a></span>
As you must have figured out, its the MSOLayout_ToggleLayoutMode()
function which does all the magic of turning the current page into Edit page. This javascript also calls the server side code which executes this statement
WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode;
//(This can also be demonstrated, but its beyond scope)
Armed with this knowledge, we can build a simple webcontrol which we will switch the page into Edit mode and vice versa.
Below is the code for the same. Its the simplest webcontrol you will see ever.
using System;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.UI;
namespace SPUtil
{
public class SPEditMode:System.Web.UI.WebControls.WebControl
{
HtmlAnchor btnLink;
protected override void CreateChildControls()
{
WebPartManager wp = WebPartManager.GetCurrentWebPartManager(Page);
const string url="javascript:MSOLayout_ToggleLayoutMode();";
btnLink = new HtmlAnchor();
if (wp.DisplayMode == WebPartManager.BrowseDisplayMode)
btnLink.InnerText = "Edit Page";
else if (wp.DisplayMode == WebPartManager.DesignDisplayMode)
btnLink.InnerText = "Exit Edit Mode";
else
btnLink.Visible = false;
btnLink.HRef = url;
Controls.Add(btnLink);
base.CreateChildControls();
}
}
}
I have used HtmlAnchor
rather than LinkButton
or SPLinkButton
since its lightweight on the server and We are not performing any special processing which is present in server controls.
One point to be worth noting: This link would be visible to all including visitors. For used in practical scenarious, the control should be hidden for other than members and Administrators.
I was using this link in user's MySite and hence I did not have that case :)
Posted by Madhur at 7:43 PM 1 comments
Filter webparts in WSS are a great way to provide filtering in many different webparts like List View, Business Data Catalog, Excel Web Access etc.
In this post, we will see how to create a simple filter webart which provides values to pivot table filter cell.
I am mentioning pivot table filter cell exclusively because the filter webpart examples on MSDN has to be slightly modified to provide values
to filter cell.
Basically, we are building a filter provider which
ITransformableFilterValues
interface.public virtual ReadOnlyCollection<string> ParameterValues
.SetConnectionInterface()
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using aspnetwebparts = System.Web.UI.WebControls.WebParts;
using wsswebparts = Microsoft.SharePoint.WebPartPages;
using System.Collections.ObjectModel;
namespace ExcelFilters
{
public class ExcelFilters : aspnetwebparts.WebPart, wsswebparts.ITransformableFilterValues
{
CheckBoxList cblRegionList;
ListItem cbitemRegion;
string[] countries = new string[]
{ "Canada", "Central America", "Mexico", "South America", "United States",
"Albania", "Andora", "Austria", "Aizerbejan", "Belarus", "belgium",
"Bosnia and Hersegovina", "Bulgaria" };
public virtual bool AllowMultipleValues
{
get
{
return false;
}
}
public virtual bool AllowAllValue
{
get
{
return true;
}
}
public virtual bool AllowEmptyValue
{
get
{
return false;
}
}
public virtual string ParameterName
{
get
{
return "Geography";
}
}
public virtual ReadOnlyCollectionParameterValues
{
get
{
string[] values = this.GetCurrentlySelectedGeographies();
Listparam=new List ();
foreach (string str in values)
{
if(!string.IsNullOrEmpty(str))
param.Add(str);
}
return values == null ?null :new ReadOnlyCollection(param);
}
}
protected override void CreateChildControls()
{
cblRegionList = new CheckBoxList();
cblRegionList.AutoPostBack = true;
Controls.Add(cblRegionList);
foreach (string region in countries)
{
cbitemRegion = new ListItem();
cbitemRegion.Text = region;
cblRegionList.Items.Add(cbitemRegion);
cbitemRegion = null;
}
base.CreateChildControls();
}
[aspnetwebparts.ConnectionProvider("Region Filter", "ITransformableFilterValues", AllowsMultipleConnections = true)]
public wsswebparts.ITransformableFilterValues SetConnectionInterface()
{
return this;
}
public string[] GetCurrentlySelectedGeographies()
{
String[] choices = new String[countries.Length];
bool anythingSelected = false;
for (int i = 0; i < cblRegionList.Items.Count; i++)
{
if (cblRegionList.Items[i].Selected)
{
anythingSelected = true;
choices[i] = cblRegionList.Items[i].Text;
}
}
if (!anythingSelected)
choices = null;
return choices;
}
protected override void RenderContents(HtmlTextWriter output)
{
this.EnsureChildControls();
RenderChildren(output);
}
}
}
Now, rather than explaining the simple webpart, which is already explained by Microsoft, I will point out key points which differentiates it from the examples at many places.
If we notice GetCurrentlySelectedGeographies()
method, it returns the string array of selected geographies. However, the length of this string array is constant and is equal to number of selectable items, which causes the other items in string array to become null
.
In the MSDN example here the string array is directly passed by converting it to ReadOnlyCollection
of strings. This will not work since it includes the null items
in the array as well.
string[] values = this.GetCurrentlySelectedGeographies();
return values == null ?null :new ReadOnlyCollection(values);
Pivot table Report filter cell, expects a Collection of values only which are selected. Thus we need to modify the code as follows
string[] values = this.GetCurrentlySelectedGeographies();
Listparam=new List ();
foreach (string str in values)
{
if(!string.IsNullOrEmpty(str))
param.Add(str);
}
return values == null ? null :new ReadOnlyCollection(param);
This code snippets, creates a new List which includes all the string objects except the null items from the original string array which is returned by GetCurrentlySelectedGeographies()
Posted by Madhur at 10:18 AM 4 comments
Continuing the series of articles on Enterprise Library, I have written the first article
on the implementation of Logging Application Block in MOSS 2007. Due to inclusion of formatted code and images, I have directly uploaded this on Codeproject.
The article can be viewed here
Posted by Madhur at 11:43 AM 0 comments
The seven application blocks are:
\Program Files\Microsoft Enterprise Library
folder. Posted by Madhur at 7:30 AM 1 comments
I have recently written my first article on Codeproject.
The article describes the development of AJAX enabled webpart on MOSS 2007 SP1.
The cool thing about it is the that it also utilizes the AJAX Control Toolkit including programmatically adding and styling TabContainer and TabPanel controls which can be quite tricky for a beginner. The article can be found here:
http://www.codeproject.com/KB/sharepoint/RssReaderAjax.aspx
Posted by Madhur at 9:39 PM 0 comments
Recently I developed an RSS Reader webpart which would take the RSS URL of list to render its feeds. Very much same like the out of the box webpart with the exception that it was AJAX enabled. I would post the details of that part on the blog when I am finished.
An idea came to me that wouldn’t it be nice to also enable users to just give the list URL rather than RSS URL since would reduce the few steps on the user’s side. I thought it would be just a matter of accessing the RssUrl property of SPList object, but to my surprise it was not to be. There is no property such property in the API, so I decided to write my own function for it.
Let’s analyze the RSS URL of a list or a library. Whenever the user clicks on View RSS feed on a library, here is how SharePoint constructs the URL:
Listfeed.aspx is the inbuilt RSS viewer of sharepoint which accepts a parameter which is the GUID of the list. %2D tokens refer to ‘-‘characters which exist inside the GUID. Considering all this, it’s easy to write a function which will return the RSS URL. Here is the code for the same:
private string MakeRssUrl(string rawurl)
{
try
{
Uri url = new Uri(rawurl, UriKind.Absolute);
if (url.GetLeftPart(UriPartial.Path).Contains(“_layouts/listfeed.aspx”))
{
return rawurl;
}
else
{
string rssurl;
using (SPWeb web = new SPSite(rawurl).OpenWeb())
{
SPList list = web.GetListFromUrl(rawurl);
rssurl = web.Url + "/_layouts/listfeed.aspx?list=" + list.ID;
return rssurl;
}
}
}
catch (UriFormatException e)
{
return string.Empty;
}
}
The code is pretty self explanatory. The argument to function is list URL or RSS url. We first check if the URL is RSS URL itself, and if it is we just return. Otherwise, if it’s a list URL, we create a SPList instance, grap the GUID and contatenate it with the site URL and listfeed.aspx.
Note that the function does not validate if the given URL was actually a valid list URL or not. The exception handling for that case should be left to the caller of the function.
Posted by Madhur at 11:30 PM 1 comments