Fear and Loathing
Gonzo blogging from the Annie Leibovitz of the software development world.
-
SharePoint Forums 1.2 Released to the wild
Okay, here it is kids, the August (1.2) release of the SharePoint Forums Web Part. This release includes the following features/fixes:
New
- Navigation menu to quickly jump to anywhere on the system
- Ability to place forums and categories in whatever display order you want
- Topic title/full body message search with links to topics/forums
- Ability to configure date format displays
Fixed
- Support for ASP.NET 2.0 installations on WSSv2 and SP2
- Order of forums is fixed to allow “bumping” of topics
- Post count display fixed on home page
- Last post date/time display fixed
Changed
- Topics now require a subject before being created
- When replying to a specific message (not the entire thread) you can now preview the message you’re replying to
Sounds like fun? Go grab it here. Just install the MSI over the old version. Your data files will not be affected. If you are upgrading from 1.1 then please follow these instructions (included in the DrinkMe.txt file) to perform the upgrade:
If you are upgrading from version 1.1 to 1.2 please do the following:
- Install the 1.2 MSI
- Add the following to web.config anywhere inside the <configuration> section:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="BilSimser.SharePoint.WebParts.Forums" publicKeyToken="e516dadc23877c32" />
<bindingRedirect oldVersion="1.1.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime> - Perform and IISRESET
- Refresh the page where your Forums Web Part lives
- Voila! Version 1.2.
Note: If you’re still running 1.0 you can do the same, just change 1.1.0.0 to 1.0.0.0.
Please let me know via email if you have any questions/problems.
-
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:
1 /*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:
7 public class TestMenu8 {
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.
-
SharePoint Forums 1.2 Sneak-a-peek
The work is almost done on version 1.2 of the SharePoint Forums Web Part. The release will go out later tonight after I chow down some food and build the package. A full list of changes will accompany the post when the release goes out but here’s some screenies of what’s coming down the pipe.
Replies with previews:
Full text search on titles and messages:
Sortable Forums and Categories:
See ya in a few hours!
-
Custom date formatting with SharePoint Forums
I’m just getting ready to release version 1.2 of the SharePoint Forums Web Part. One feature was the ability to control the date and time display for users. This has been added and documented on the CodePlex wiki here.
The SharePoint Forums Web Part (version 1.2 and higher) provides the ability to set the default date/time format when displaying dates in the system. This is used on the last post of a topic, individual messages, and user profiles. Basically anywhere a date/time stamp is displayed you have control over the format.
The format is based on how your server is set so "d" on a US setting is Month/Day/Year whereas on a Canadian setting it's Day/Month/Year. The following values will produce the output shown for August 7, 2006 at 11:30:00 AM:
d - 8/7/2006
D - Monday, August 07, 2006
f - Monday, August 07, 2006 11:30 AM
F - Monday, August 07, 2006 11:30:00 AM
g - 8/7/2006 11:30 AM
G - 8/7/2006 11:30:00 AM
m,M - August 07
r,R - Mon, 07 Aug 2006 11:30:00 GMT
s - 2006-08-07T11:30:00
t - 11:30 AM
T - 11:30:00 AM
u - 2006-08-07 11:30:00Z
U - Monday, August 07, 2006 5:30:00 PM
y - August, 2006You can also create a custom pattern using the following formatters. This means that if you don't like any of the formats above, you can just create your own and really personalize the forums.
d - The day of the month. Single-digit days will not have a leading zero.
dd - The day of the month. Single-digit days will have a leading zero.
ddd - The abbreviated name of the day of the week, as defined in AbbreviatedDayNames.
dddd - The full name of the day of the week, as defined in DayNames.
M - The numeric month. Single-digit months will not have a leading zero.
MM - The numeric month. Single-digit months will have a leading zero.
MMM - The abbreviated name of the month, as defined in AbbreviatedMonthNames.
MMMM - The full name of the month, as defined in MonthNames.
y - The year without the century. If the year without the century is less than 10, the year is displayed with no leading zero.
yy - The year without the century. If the year without the century is less than 10, the year is displayed with a leading zero.
yyyy - The year in four digits, including the century.
gg - The period or era. This pattern is ignored if the date to be formatted does not have an associated period or era string.
h - The hour in a 12-hour clock. Single-digit hours will not have a leading zero.
hh - The hour in a 12-hour clock. Single-digit hours will have a leading zero.
H - The hour in a 24-hour clock. Single-digit hours will not have a leading zero.
HH - The hour in a 24-hour clock. Single-digit hours will have a leading zero.
m - The minute. Single-digit minutes will not have a leading zero.
mm - The minute. Single-digit minutes will have a leading zero.
s - The second. Single-digit seconds will not have a leading zero.
ss - The second. Single-digit seconds will have a leading zero.
f - The fraction of a second in single-digit precision. The remaining digits are truncated.
ff - The fraction of a second in double-digit precision. The remaining digits are truncated.
fff - The fraction of a second in three-digit precision. The remaining digits are truncated.
ffff - The fraction of a second in four-digit precision. The remaining digits are truncated.
fffff - The fraction of a second in five-digit precision. The remaining digits are truncated.
ffffff - The fraction of a second in six-digit precision. The remaining digits are truncated.
fffffff - The fraction of a second in seven-digit precision. The remaining digits are truncated.
t - The first character in the AM/PM designator defined in AMDesignator or PMDesignator, if any.
tt - The AM/PM designator defined in AMDesignator or PMDesignator, if any.
z - The time zone offset ("+" or "-" followed by the hour only). Single-digit hours will not have a leading zero. For example, Pacific Standard Time is "-8".
zz - The time zone offset ("+" or "-" followed by the hour only). Single-digit hours will have a leading zero. For example, Pacific Standard Time is "-08".
zzz - The full time zone offset ("+" or "-" followed by the hour and minutes). Single-digit hours and minutes will have leading zeros. For example, Pacific Standard Time is "-08:00".
: - The default time separator defined in TimeSeparator.
/ - The default date separator defined in DateSeparator.
% c - Where c is a format pattern if used alone. The "%" character can be omitted if the format pattern is combined with literal characters or other format patterns.
\ c - Where c is any character. Displays the character literally. To display the backslash character, use "\\".Note: these are all standard .NET formaters for DateTimeInfo, but documented here for users of the Web Part who are not .NET developers.
-
Comment spam on the rampage
Holy mother of Isis. What’s with the comment spam on weblogs these days? I’m getting close to 100 comments a day that are all spam. Luckily I have anonymous comments turned off and the spam filter on Community Server is recognizing these as spam and not publishing them. Still, is anyone else getting this much comment spam? It’s been quiet for sometime now but the last week or two things have just gone nuts. Talk about the coming apocalypse, Nostradamus sure didn’t see this one coming.
-
Internet Exploder 7 - An absolute train wreck
There have been a lot of great train wrecks throughout movie history that stick in mind. The Fugitive, Back to the Future III, and Under Siege 2 to name a few. Tonight I went through the painful process of creating my own train wreck, namely Internet Explorer 7 Beta 3.
I’ll admit that I don’t have the average desktop. I’m running both versions of the .NET framework, I have both the 2003 and 2005 flavours of Visual Studio, there’s the GAT and the GAX, a dozen or so SDKs and toolkits, Virtual Server and Virtual PC, Subversion, Groove, Windows Live Messenger, OneNote, PC-Cillin, and an army of small little tools, some that sit in my tray and are always running (like PureText). However I at least expect IE to at least work. A little?.
First off I run http://localhost as my home page. It’s just a static HTML web page with links to local projects so I don’t forget. Yeah, did you read that? Static HTML. No fancy scripts, no complicated ActiveX controls. Just a bleepin’ web page. And IE 7 says this to me:
WTF? You compiled my HTML page and got an error. How nice. I guess nobody told you that HTML pages don’t get compiled. I checked the source of the page again, just in case I did something silly like oh, I don’t know, added some code. Nope. A HTML compliant page with barely any text on it and no graphics (Jakob Nielsen would be proud of me). I could get past this but each and every time I tried to edit the options to allow “intranet” access (like that’s a bad thing?) it hung. Complete and utter hang. So much so that nothing would work or allow me to click on anything. I shut down the process and tried it again. Same thing.
No POS browser is going to get the better of me so I thought I would be smart. Rather than clicking in the error message area that pops up (or whatever that band of death is called) I thought I would be sneaky and go through the menu to invoke the option from there. Of course IE figured out what was going on and promptly hung again. And again. And again.
I did manage to grab the Google toolbar and navigate to the Google home page. Of course that’s about all I could do and even though the browser part of the app was refreshing, the rest of the screen (i.e. all of the controls) were stuck in UI limbo. Here’s a shot of all the other windows in my system overlapping and making browsing rather difficult, as I frantically clicked to get back some semblance of a browser:
No, that’s just not right. What really peeved me off was that it would hang no matter what option I tried (including responding to dialogs that it created for me). I even tried to un-install any extra toolbars I had (Developer toolbar and Google) but it still wasn’t a happy camper, and neither was I. In fact, just launching it and IE decided to max out my CPU for the rest of it’s pathetic existence:
Nice.
Okay, that was it. This waste of bytes had to go and go fast. I hunted it down in the Add/Remove Programs dialog (how nice of MS to put it somewhere easy to find) and immediately nuked it. Of course even on it’s final throes of death it still mocked me:
No, I did not install anything after IE. I just installed you! WTF? Apparently IE is not only impossible to run on my system but also brain dead because it *thinks* something has happened since it was installed a mere few minutes ago. I guarantee you it isn’t true so wherever it’s getting this information from, it’s wrong. Yes, Atlas is installed on my system but that was done weeks ago. Stupid program.
Once I finally got IE6 back and it was running I wanted to check on something. An interesting stat was IE vs FireFox running my static HTML page. Here they are side by side with my single static HTML page loaded:
The first number is the number of threads. IE has 12 running, FF has 8. Whatever, no biggie deal there. Then comes USER objects and GDI objects (I have these available in Process Explorer to track resource leaks in WinForm projects). IE has over triple the number of USER objects FF has and over double GDI objects (even Photoshop doesn’t have this many GDI objects!). Okay, I guess people don’t care but you would think the numbers would be small as the program doesn’t do much. I mean a browser is just a single window, a menu, a few buttons, a toolbar and a status bar. To me, that’s a lot of objects for such a simple UI but then I prefer to be a minimalist when it comes to these things. The last number is the memory footprint so no surprise there, IE gobbles up twice as much memory as FF and it’s not really doing anything yet.
I’ve bitched about this in the past and this is a new build of my OS so I can’t blame it on that. Lots of people run it successfully so the cheese stands alone here. I can only bring it down to brass tacks: my machine doesn’t like IE 7. Plain and simple. Of course the problem is that now, someday, I’m going to have to run this puppy as my default browser. Yes, by then it’ll be released and not a beta but this is B3 for petes sake. Shouldn’t it work in the majority of scenarios by now? Is my machine that odd and different. Is there some terrible tool running that IE just flat out refuses to work?
The mind boggles.
-
A rolling blog gathers a lot of knowledge
Most times I see myself as a giant katamari and the internet is all stuff I can just roll over, pick up, and make my brain grow bigger. This blog isn’t one of those things, but the article linked here is.
Michael Feathers has a great article on what he calls “sensing variables”, variables introduced into a long piece of code that can be used to verify refactorings. In a nutshell (hey, how did I get into this nutshell?) it captures the state of something for recovery later and allows you to introduce refactorings (say rearranging code) with the comfort that things haven’t changed without your intent.
Very cool as it’s always difficult to find a way to know the state of things when you’re trying to program for a stateless environment. The other thing is that while unit test rock my world, I find it very difficult sometimes to get them to poke and prod into classes to see what’s going on. I only rely on public properties and methods (I don’t believe in the reflection gig trying to test private accessors) and try to stay away from “out” parameters as often as I can (I really don’t like knowing a variable goes in one way and out another without knowing what’s going on in between) so I can only test what’s returned. Often it’s hard to write a test that really gets at the heart of what’s going on, without exposing everything and blowing off basic tenets of OO like encapsulation.
Anyways, great article and simple technique for this kind of thing. It’s easy to implement and works well so feel free to check it out here.
-
Dead or alive, you're coming with me
Just a short post today (actually, now that it's finished it's pretty long but there's no much technical content here) as I'm shuffling things around schedule wise and just wanted to let you know where things are. This also talks about some dead projects that are being resurrected and others that are being reborn. Yeah, I'm all about software reincarnation.
First up is scheduling for the SharePoint Forums Web Part. Releases are going to be the first Monday of each month so if the first is a Tuesday, it shuffles ahead to the next week (the 6th of the month). Yeah, I could choose the day before but then it wouldn't give me those extra few days so cut me some slack. The next release of the forums is 1.3 (it was called 2.0 but it hasn't got that mature yet) and will work in WSS ASP.NET 2.0 setups and implement various bug fixes and new features. The 2.0 release will be the one that fully leverages MOSS 2007 as there are some major changes to architecture and the deployment (it will be a solution deployment rather than an MSI, and available as a feature you can turn on or off). That is expected to come along in the September drop.
The SharePoint Knowledgebase release will be the middle of each month (even with a vast team of coding monkeys, I can only get so much done on the 1st of any given month) and the first release has been pushed out the middle of September. I was going to have a release for August, but there's just too much going on where I'll be incognito (i.e. without 'puter) that I can't spin it. The first release will be pretty close to fully featured as there's only so much a knowledge base can do, however please post your ideas in the forums (there hasn't been much activity there) and let me know what you want to see (or confirm that it's there).
As for dead or resurrected projects, there are two. First is the highly anticipated (based on emails I get) SharePoint Builder. This is my visual Xml editor for ONET.XML and SCHEMA.XML files. Yes, it's still alive and kicking however while I was waiting for a stable release of MOSS, other things stacked up so it got shuffled to the back burner. It's back and you'll be hearing from it soon. It's now using the Smart Client Software Factory from Microsoft and has a lot of great features (like remote editing of XML files) and will have full support for MOSS 2007 (while maintaining compatibility with 2003 site definitions). Watch for it in the Sept-Oct timeframe and new screenshots/news in the coming weeks.
The final project is one that hurts me, but makes sense. A couple of months ago I launched my SharePointForge site. Basically a project hosting site for SharePoint projects. The problem was that I had my fingers in too many cookie jars so I couldn't dedicate the time I wanted to the site. CodePlex came and is providing a good place for hosting projects (strangely enough SharePointForge basically looked like CodePlex but on steroids, even before I had seen CodePlex) and really I wasn't able to get into the business of hosting peoples source code. So SharePointForge is dead (sort of) and is being reborn. Like the Phoenix, it's transmogrifying into a new site. It's much like the old SharePointForge concept, but won't offer hosting. I can't announce what this is about, but you'll be hearing and seeing the site in the next couple of weeks.
Most of the shuffle is due to a vacation I'm taking (gasp, horror of horrors). As a consultant, it's actually hard to take a vacation because a) you don't get paid for it and b) you're always thinking about the next project you're working on and trying to squeeze that into some insane schedule (at least I am).
Anyways, Bil is a busy boy but life is good so enjoy it.
-
It's all about balance in the universe
Seems a lot of people are scratching their heads at Micrsoft’s move to charge $1.50 per download on the Office Beta. They’re wondering (besides money I guess) what the rationale behind this move is. It’s really quite simple.
In the universe there must be balance. With the charge for the Office download, Microsoft is offsetting the cost of making the MSDN Library downloads now free. With darkness there is light. With Office there is MSDN.
Pretty clear to me ;)
-
Composite UI Application Block - Soup to Nuts - Getting Started
I’m currently helping some teams move towards creating Smart Client applications. As part of that move, I’m also introducing them to use the Composite UI Application Block (CAB) which will ease the pain of building the UI, separating it, and generally making it a better life than just writing plain old boring Windows Form apps.
So this begins a series of blogs on writing applications using CAB. The series starts super simple, with a bare minimal example and compares the differences between a regular WinForm app and one written using the CAB. In this series, we’ll just keep building on each example to another and finish off with an n-tier, service-oriented solution that employs the CAB and does some pretty cool stuff. I won’t reveal what the app is but you can figure it out as we go along.
The next series to follow-up this series will go beyond just the CAB and describe the Smart Client Software Factory (SCSF) which not only uses CAB but adds a million other things. Think of CAB as Windows Forms on steroids and the Smart Client Software Factory as CAB on steroids. It’s going to be a blast.
By now, you’re probably wondering why a little ol’ SharePoint MVP like me is blubbering on about writing Smart Clients but hang in there, they’ll be more than your share of SharePoint stuff by the time we’re finished.
Rules of Engagement
Just a couple of notes on this blog series. All the examples are written in C#. If you’re looking for VB.NET samples you won’t get them here as I just prefer C# (feel free to build your sample in VB.NET if that’s your cup’o’tea). Also these samples are built with Visual Studio 2005 just because a) the CAB is .NET 2.0 based and b) the SCSF is Visual Studio 2005 based. I think there might be a version of CAB for 1.1 (not sure) but Smart Client development and Click Once was never great with .NET 1.1 and it’s 2006 so get off yer 1.1 butts and move on up to the new neighbourhood.
Getting Started
Okay, let’s get this party started. We have to walk before we run so this blog entry is just going to create the minimal app. We’ll highlight the differences between what you get with an auto-generated WinForm app vs. what you need to do to create the minimal CAB app. It doesn’t do anything at this point (not even “Hello World” on the screen) but every journey starts with the first step.
To get going:
- Install the CAB using the link above and follow the instructions for installation
- Create a new Windows Application using the Create Project option in Visual Studio. Just the typical application (call it WindowsApplication1) with a single Windows Form.
- Add a reference to the following assemblies: Microsoft.Practices.Composite.UI; Microsoft.Practices.Composite.UI.WinForm; Microsoft.Practices.ObjectBuilder.
Next we’re going to create a WorkItem. A WorkItem is A WorkItem is a run-time container for components that are working together to fulfill a use case. These components may consist of SmartParts (no, not those SmartParts), controllers, services, UIElements, and other components. You can use a WorkItem to encapsulate different use cases or areas of an application to share events and state. However, if you overuse WorkItems and make them too fine grained, or if you build your WorkItem classes inconsistently, you may end up with an application that is difficult to maintain. You need at least one WorkItem in your application so let’s create one:
- Create a new class called Form1WorkItem
- Add Microsoft.Practices.CompositeUI to the using statements at the top of the file
- Change the Form1WorkIem class to inherit from the WorkItem class
Your Form1WorkIem class should look like this now:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using Microsoft.Practices.CompositeUI;
5
6 namespace WindowsApplication1
7 {
8 public class Form1WorkItem : WorkItem
9 {
10 }
11 }
What we’ll do to CAB-enable the application is one more change. This is to the Program.cs file that is the main entry point for the application. Here’s the default one from Visual Studio:
1 using System;
2 using System.Collections.Generic;
3 using System.Windows.Forms;
4
5 namespace WindowsApplication1
6 {
7 static class Program
8 {
9 /// <summary>
10 /// The main entry point for the application.
11 /// </summary>
12 [STAThread]
13 static void Main()
14 {
15 Application.EnableVisualStyles();
16 Application.SetCompatibleTextRenderingDefault(false);
17 Application.Run(new Form1());
18 }
19 }
20 }
Nothing special here but we’re going to transform this by doing the following:
- Add Microsoft.Practices.CompositeUI.WinForms to the using statements of the file
- Change the Program class from static to public
- Inherit from the FormShellApplication class in CAB
- Modify the Main method to support CAB
Here’s the modified version of the Program class that supports the CAB (also note the change from static to public):
1 using System;
2 using System.Collections.Generic;
3 using System.Windows.Forms;
4 using Microsoft.Practices.CompositeUI.WinForms;
5
6 namespace WindowsApplication1
7 {
8 public class Program : FormShellApplication<Form1WorkItem, Form1>
9 {
10 /// <summary>
11 /// The main entry point for the application.
12 /// </summary>
13 [STAThread]
14 static void Main()
15 {
16 new Program().Run();
17 }
18 }
19 }
The only difference here is that we derive our application from FormShellApplication (a generic class in the CAB), passing the WorkItem class and the Form class we created. Also the startup in Main has changed to call the Program classes run (defined in the FormShellApplication class) rather than the standard Application.Run(). As we’re setting the value of the form in the FormShellApplication via generics so there’s no need for us to pass the Form class to the Application class like we did in regular .NET. There’s a nice blog entry here by Brad Wilson on describing the FormShellApplication class (and other classes in the CAB) which you might want to take a peek at.
That’s it. Build the solution (hopefully you shouldn’t have any errors) and run the app with F5 (or Ctrl+F5).
Amazing huh? This looks and behaves no different than a regular WinForm app but it’s now CAB enabled and almost ready to go. As I said, this is a super simple example and doesn’t even display “Hello World” or anything. With the tires kicked, we’re ready to start adding form and functionality the CAB way!
So what did we get out of this post? Hopefully you can see the (minor) differences between a regular Windows application and a CAB-enabled one (pretty simple huh?) and your project is now ready to start using features of the Composite UI Application Block. We’ll start exploring what you can do in the next entry in this series.