SharePoint Menus in C#
There are a lot of great articles out there that talk about how you can leverage the SharePoint style of drop-down menus (you know that cool looking javascript menu) and creating your own. All of them require you to write some HTML and/or JavaScript and embed this into a CEWP on a page. This is fine, but when you’re building your own Web Parts, you might want something a little simpler.
In working on the SharePoint Forums Web Part, I wanted to create a drop-down menu populated by some of the links in the system and the categories and forums so someone could easily jump to a forum immediately. Most forums use a standard web drop-down list but since I had the SharePoint menu javascript already at my disposal I thought I would use it. So I put together this little class that creates me a menu, lets me add items to it, then just spits out the HTML that I can render to my page. Here’s the full class:
2 * SharePointMenus.cs
3 * Dynamic SharePoint-style menus in C#
4 *
5 * Copyright (c) 2006 by Bil Simser, bsimser@shaw.ca
6 *
7 * This work is licensed under the Creative Commons
8 * Attribution-NonCommercial-ShareAlike 2.5 License.
9 *
10 * To view a copy of this license, visit
11 * http://creativecommons.org/licenses/by-nc-sa/2.5/
12 * or send a letter to Creative Commons, 559 Nathan
13 * Abbott Way, Stanford, California 94305, USA.
14 */
15
16 using System;
17 using System.Text;
18 using System.Xml;
19
20 namespace BilSimser.SharePoint.WebParts.Forums.Utility
21 {
22 /// <summary>
23 /// Small helper class that will build out a menu in
24 /// the SharePoint drop down style for adding to HTML output.
25 /// </summary>
26 public class SharePointMenu
27 {
28 #region Fields
29
30 private string _header;
31 private XmlElement _currentNode;
32 private XmlElement _rootNode;
33 private XmlDocument _xmlDocument;
34
35 #endregion
36
37 #region Constructors
38
39 public SharePointMenu(string title)
40 {
41 createHeader(title);
42 createXmlDocument();
43 }
44
45 #endregion
46
47 #region Properties
48
49 private string Header
50 {
51 set { _header = value; }
52 get { return _header; }
53 }
54
55 #endregion
56
57 #region Public Methods
58
59 public void AddMenuItem(string title, string url)
60 {
61 AddMenuItem(title, url, string.Empty);
62 }
63
64 public void AddMenuItem(string title, string url, string imageUrl)
65 {
66 XmlElement childNode = _xmlDocument.CreateElement("ie:menuitem", "http://www.tempuri.com");
67 childNode.SetAttribute("id", "MSO_MyMenu_Link1");
68 childNode.SetAttribute("title", title);
69 if(imageUrl != string.Empty)
70 childNode.SetAttribute("iconSrc", imageUrl);
71 childNode.SetAttribute("onMenuClick", string.Format("javascript:window.location.href='{0}';", url));
72 childNode.InnerText = title;
73 _currentNode.AppendChild(childNode);
74 }
75
76 public void AddSeparator()
77 {
78 XmlElement childNode = _xmlDocument.CreateElement("ie:menuitem", "http://www.tempuri.com");
79 childNode.SetAttribute("type", "separator");
80 _currentNode.AppendChild(childNode);
81 }
82
83 public void AddSubMenu(string title)
84 {
85 AddSubMenu(title, string.Empty);
86 }
87
88 public void AddSubMenu(string title, string imageUrl)
89 {
90 XmlElement childNode = _xmlDocument.CreateElement("ie:menuitem", "http://www.tempuri.com");
91 childNode.SetAttribute("type", "submenu");
92 if(imageUrl != string.Empty)
93 childNode.SetAttribute("iconSrc", imageUrl);
94 _currentNode.AppendChild(childNode);
95 _currentNode = childNode;
96 AddLabel(title);
97 }
98
99 public void CloseSubMenu()
100 {
101 _currentNode = _rootNode;
102 }
103
104 public void AddLabel(string title)
105 {
106 XmlElement childNode = _xmlDocument.CreateElement("ie:menuitem", "http://www.tempuri.com");
107 childNode.SetAttribute("type", "label");
108 childNode.InnerText = title;
109 _currentNode.AppendChild(childNode);
110 }
111
112 public override string ToString()
113 {
114 StringBuilder sb = new StringBuilder();
115 sb.Append(Header);
116 sb.Append(_xmlDocument.InnerXml);
117 return sb.ToString();
118 }
119
120 #endregion
121
122 #region Private Methods
123
124 private void createXmlDocument()
125 {
126 _xmlDocument = new XmlDocument();
127 _rootNode = _xmlDocument.CreateElement("menu", "http://www.tempuri.com");
128 _rootNode.SetAttribute("id", "MSO_MyMenu");
129 _rootNode.SetAttribute("class", "ms-SrvMenuUI");
130 _xmlDocument.AppendChild(_rootNode);
131 _currentNode = _rootNode;
132 }
133
134 private void createHeader(string title)
135 {
136 Header = string.Format("<div class=\"ms-HoverCellInActive\" "+
137 "onmouseover=\"this.className='ms-HoverCellActive'\""+
138 "onmouseout=\"this.className='ms-HoverCellInActive'\">"+
139 "<a id=\"MSO_MyMenuLink\" title=\"{0}\" style=\'CURSOR: hand\''+
140 "onclick=\"MSOWebPartPage_OpenMenu(MSO_MyMenu, this);\""+
141 "tabindex=\"0\">{0}<img alt=\"{0}\" src=\"/_layouts/images/menudark.gif\""+
142 "align=\"absBottom\"></a></div>", title);
143 }
144 #endregion
145 }
146 }
It’s not beautiful and there are a lot of improvements you can make. For example, some of the names are hard coded and should be generated dynamically and keeping track of the submenu levels should be something managed outside of the class. However it works and is easy to use.
To use it, just drop this class into your project and you can create a menu with a few lines of code like this:
8 {
9 public void CreateHtmlMenu()
10 {
11 SharePointMenu menu = new SharePointMenu("My Menu");
12 menu.AddMenuItem("First Item", "http://www.microsoft.com");
13 menu.AddMenuItem("Second Item", "http://www.slashdot.org");
14 menu.AddSeparator();
15 menu.AddMenuItem("Last Item", "http://www.example.com");
16 }
17 }
That will get you a simple menu with a few items. Then in your RenderWebPart, or wherever you’re writing out the Web Part contents just write it out:
19 public override void RenderWebPart(HtmlTextWriter writer)
20 {
21 SharePointMenu menu = new SharePointMenu("My Menu");
22 menu.AddMenuItem("First Item", "http://www.microsoft.com");
23 menu.AddMenuItem("Second Item", "http://www.slashdot.org");
24 menu.AddSeparator();
25 menu.AddMenuItem("Last Item", "http://www.example.com");
26 writer.WriteLine(menu.ToString());
27 }
You can also create multiple level menus and submenus. Just call the AddSubMenu method(s) in the class (with or without an image). When you call AddSubMenu, any future calls to AddMenuItem will just add it to that submenu. When you want to back out of the menu, just call the CloseSubMenu method. Like I said, it’s not pretty as it really only supports 1 level of menus and will always back out to the root. However it can be modified and updated with a little work to support unlimited submenus, dynamic generation of IDs, etc. Use your imagination.
Here’s the menu for the SharePoint Forums Web Part which sparked creating this class. The categories and forums are dynamically generated based on what the user can see, etc. and the menu is built up based on options in the system and what the user can do. Looks pretty slick and only took a few lines of code:
So have fun with it and feel free to modify it. If you do extend/enhance it let me know and I’ll update the resource. You can grab the class file here for use in your program. It’s released under the Creative Commons License.