You are hereSharePoint v3: Recreating the Quick Launch Menu


SharePoint v3: Recreating the Quick Launch Menu


By hagrin - Posted on 07 February 2007

UPDATE: 2009 June 17th - Please see the comment by David in the comments section. His fix is the best fix I have seen for this problem.

If you see any improvements that I can make, let me know by leaving me a comment. Hope this helps someone.

Versioning

  1. Version 1.2 - (2009 June 17) - Much better solution posted in comments by user David.
  2. Version 1.1 - (2007 May 2) - Bug fixes which include:
    • Applying Quick Launch logic that is used in the SharePoint WSS 40 Free Application templates.
    • Wrapping data retreived from the database and other sources in System.Web.HttpUtility.UrlPathEncode() to prepare for URL formation and usage.
    • Colorized the comments (I'm looking for a Drupal module to automatically do this for me)
  3. Version 1.0 - (2007 Feb 7) - Original Article on recreating the SharePoint v3 Quick Launch through a Web Part

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Navigation;

namespace InfoViewer
{
public class SQLQuickLaunch : System.Web.UI.WebControls.WebParts.WebPart
{
protected override void RenderContents(System.Web.UI.HtmlTextWriter output)
{

base.RenderContents(output);
try
{
string strURL = Page.Request.Url.AbsoluteUri;
string[] arrURL = strURL.Split("/".ToCharArray());
SqlConnection SQLConnection = new SqlConnection();
DataSet DataSet1 = new DataSet();
DataSet DataSet2 = new DataSet();
DataSet DataSet3 = new DataSet();

string strGUID = "";
string strRootGUID = "<>";
string strListGUID = "";
string strRootURL = "<>";
SQLConnection.ConnectionString = "Data Source=RMSSERVER\\OFFICESERVERS;Initial Catalog=WSS_Content;Integrated Security=SSPI;";
SQLConnection.Open();
string SQLQuery = "select id, fullurl from webs where siteid = '" + strRootGUID + "' and fullurl = '" + arrURL[3] + "'";
SqlDataAdapter DataAdapter = new SqlDataAdapter(SQLQuery, SQLConnection);
DataAdapter.Fill(DataSet1);
if (DataSet1.Tables[0].Rows.Count > 0)
{
strGUID = DataSet1.Tables[0].Rows[0][0].ToString();
arrURL[3] = arrURL[3];
}
else
{
strGUID = "";
arrURL[3] = "";
}
DataSet1 = new DataSet();
SQLQuery = "select eid, numchildren, rankchild, url, name, siteid from navnodes where eidparent in (select eid from navnodes where webid = '" + strGUID + "' and siteid = '" + strRootGUID + "' and name = 'Quick Launch') and webid = '" + strGUID + "' and siteid = '" + strRootGUID + "' order by rankchild";
DataAdapter = new SqlDataAdapter(SQLQuery, SQLConnection);
DataAdapter.Fill(DataSet1);
if (DataSet1.Tables[0].Rows.Count > 0)
{
output.RenderBeginTag("div class=ms-quicklaunchouter");
output.RenderBeginTag("div class=ms-quicklaunch style=\"width:100%; border: none;\"");
output.RenderBeginTag("table cellpadding=0 cellspacing=0 class=ms-quicklaunch width=100%");
output.RenderBeginTag("tr");
output.RenderBeginTag("td class=ms-quicklaunchheader style=\"border: none;\"");
output.Write("Navigation");
output.RenderEndTag();
output.RenderEndTag();
for (int i = 0; i <= DataSet1.Tables[0].Rows.Count - 1; i++)
{
output.RenderBeginTag("tr");
output.RenderBeginTag("td");
strListGUID = DataSet1.Tables[0].Rows[i][5].ToString();
output.RenderBeginTag("table class=ms-navheader cellpadding=0 cellspacing=0 border=0 width=100%");
output.RenderBeginTag("tr");
output.RenderBeginTag("td style=width:100%;");
string strTD = "a class=ms-navheader style=\"border-style:none;font-size:1em;\" href=";
if (DataSet1.Tables[0].Rows[i][3].ToString().Substring(0, 7) == "http://")
{
output.RenderBeginTag(strTD + System.Web.HttpUtility.UrlPathEncode(DataSet1.Tables[0].Rows[i][3].ToString()));
}
else
{
output.RenderBeginTag(strTD + "http://" + strRootURL + System.Web.HttpUtility.UrlPathEncode(DataSet1.Tables[0].Rows[i][3].ToString()));
}
output.RenderBeginTag("b");
output.Write(DataSet1.Tables[0].Rows[i][4]);
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
if (int.Parse(DataSet1.Tables[0].Rows[i][1].ToString()) > 0)
{
DataSet2 = new DataSet();
SQLQuery = "select eid, numchildren, rankchild, url, name, DocID from navnodes where eidparent in (select eid from navnodes where eid = '" + DataSet1.Tables[0].Rows[i][0].ToString() + "' and webid = '" + strGUID + "' and siteid = '" + strRootGUID + "') and webid = '" + strGUID + "' and siteid = '" + strRootGUID + "' order by rankchild";
DataAdapter = new SqlDataAdapter(SQLQuery, SQLConnection);
DataAdapter.Fill(DataSet2);
for (int x = 0; x <= DataSet2.Tables[0].Rows.Count - 1; x++)
{
output.RenderBeginTag("tr");
output.RenderBeginTag("td");
output.RenderBeginTag("table class=ms-navitem width=100% border=0 cellpadding=0 cellspacing=0");
output.RenderBeginTag("tr");
output.RenderBeginTag("td style=\"width:100%;\"");
if ((DataSet2.Tables[0].Rows[x][3]) != DBNull.Value)
{
output.RenderBeginTag("a class=ms-navitem style=\"border-style:none;font-size:1em;\" href=http://" + strRootURL + System.Web.HttpUtility.UrlPathEncode(DataSet2.Tables[0].Rows[x][3].ToString()));
}
else
{
DataSet3 = new DataSet();
string strDocGUID = DataSet2.Tables[0].Rows[x][5].ToString();
SQLQuery = "select DirName, LeafName from AllDocs where id = '" + strDocGUID + "'";
DataAdapter = new SqlDataAdapter(SQLQuery, SQLConnection);
DataAdapter.Fill(DataSet3);
output.RenderBeginTag("a class=ms-navitem style=\"border-style:none;font-size:1em;\" href=http://" + strRootURL + "/" + System.Web.HttpUtility.UrlPathEncode(DataSet3.Tables[0].Rows[0][0].ToString()) + "/" + System.Web.HttpUtility.UrlPathEncode(DataSet3.Tables[0].Rows[0][1].ToString()));
}
output.Write(DataSet2.Tables[0].Rows[x][4]);
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
}
}
}
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
}
DataSet1 = null;
SQLConnection.Close();
}
catch (Exception ex)
{
output.Write(ex.Message);
}
finally
{
}
}
}
}

Have you attempted, or do you know, if it possible to create a similar .ascx control and add to a site through a feature?

@Steve -

Thanks for the comment. Although I haven't tried it, if you think about features and how they work in theory, I would have to say that the answer is yes that it would most definitely work. I might give this approach a shot since it seems recreating the quick launch has interest to the SharePoint community and I'm willing to dive deeper into more elegant solutions. I'll post here what I find probably next week.

Well done bala! Thank you for the C# code and improved stylization. In fact, I haven't really checked pixel by pixel so I should definitely do that with my code snippet above.

Btw, instead of some of the other functions I used, do you know of any WSS 3.0 SDK integration that I could use to improve the web part? I'm open to any improvements! Thanks again for contributing.

Hi
I want to create a quick launch links based on user login.

By adding code in default.master, I can create links for a user A.

When User B logs in, it shows the links of user A. When i refresh the browser of B, it shows the links of User B.

When i refresh User B browser, it shows links of User B.

I want to retain the links of each user on their login, till they logout.

If this is possible what are the things, i need to keep in mind when i'm developing this.

Awaiting your reply.

Thanks
Prasad

Prasad -

Great question and one that I have had to deal with here at work. The Quick Launch works off a completely different system than the List system, whih to me, seems like a major error on Microsoft's part. I don't see why the Quick Launch had to be structured on the backend differently and really should have just been made a list.

Why should it have been made a list? So you could perform list item security and only display/render links that users had rights to see and access.

Out of the box, SharePoint's Quick Launch doesn't seem to support item level security (there might be a feature you could add/write, but I am not aware of one currently). So, you could either look into writing a custom feature or ripping out the Quick Launch and converting the Quick Launch info into a list, applying list item security and displaying those links only if the user has the proper permissions. Those are some of the ideas I have had for handling this same problem.

Thanks hagrin. For us IT types who aren't as familiar with C#, would it be possible to post the code project for this? Not knowing much about making Custom Web Parts, I'm not exactly sure what to do with this cost specifically :)

Np anonymous. I like being able to share pieces of code that took me a while to figure out to help others.

As for how exactly to use all of this code, yikes that could take a while. I'll try and list out the steps simply and see if that can at least get you started -

1) Open up Visual Studio and create a Web Part Library project.
2) Add a .dwp file and change the info inside to accomodate your web part.
3) Add a .vb web part file and add the code I listed in my article.
4) Build the project.
5) After building the project, there will be a new .dll file in your project's bin directory. Copy that file into the bin directory of your SharePoint server.
6) Make necessary changes to your web.config file and trust file as necessary.
7) Upload .dwp file through the SharePoint web interface into the Web Part gallery.
8) In SharePoint Designer, insert the web part and drag it onto your page in Design view. Save and refresh the page in a browser.

Those are the very, very, very basic steps to using this code. If you need any more help, let me know what you're trying to do and where you are at. You can also email me (contact info on Contact page).

Hi,

This is a very detailed write up and at the same time utterly complicated. Does the same apply for MOSS? How could MS make such a mistake? I'm hopeing to find another solution, I’ll post if I do.

Thank you,

@Anon -

Yeah, although the article is complicated, it's the only way I know of to recreate the Quick Launch. However, there may be a way that's explained in the SDK, but not that I know of. Actually, thinking about it now, maybe you could create a content placeholder on the left hand side and then add the Quick Launch into that placeholder on every created page, but that doesn't seem like a good solution. To be honest, unless there is an easier way outlined in the SDK, I can't see any other way of accomplishing this.

I actually need to make a few updates to this post - I have had to change the code some to accomodate the templates released by the SharePoint team since they don't follow their own link building structure (sigh).

This approach is way too complicated.

This can be fixed with 2 edits on the default master:

http://jetlounge.net/blogs/teched/archive/2009/01/12/quick-launch-bar-navigation-missing-from-web-part-pages-in-sharepoint.aspx

David -

Excellent! Thank you for pointing this out to me. It definitely resolves the issue of adding the quick launch to the left side navigation although it did seem to add some funky rendering, but I haven't really looked into it. Nice fix - I can finally get rid of this outdated post!

I am looking for various info on sharepoint bits and am getting disillusioned with the whole platform.
There are so many work arounds, fiddly bits and aftermarket software/tips to enable what I would think to be pretty minor and basic functionality. Altering different bits of the site call for different programs, methods, It's all a bit of a mess if you ask me. I hope all the wierdness is addressed in future versions.

@Anon -

I couldn't agree more. I find that the SharePoint platform is definitely far from a polished, user friendly, admin friendly, developer friendly platform. I think CMS systems like Drupal are much more friendly to those using it and definitely easier to customize and extend.

Recent comments