14410 Views // 0 Comments // Not Rated

SharePoint Web Part Zone / Page Manager - Released On CodePlex

Have you ever tried to use custom layouts to programmatically provision web part pages via the SharePoint API? F that! It seems to me like you need to take a dependency on MOSS and the Office Server publishing infrastructure. All this just to modify a web part zone? There has to be an easier way to get tasks like these done!

Well there are a few possibilities, but nothing that pans out to be feasible. The first thing I tried was the "right way" by which you need to install MOSS, activate all kinds of features that have strict - but yet not enforced - dependencies, and then finally write code that is going to be riddled with hard-coded Guids, content types, and other sources of ulcers.

So like I said, thanks, but F - off. By "not enforced" I mean that if you try to activate these publishing features manually, and forget one or do them in the wrong order, SharePoint will blow up all other place, for example, when creating sub sites or pages of certain types.

The next approach was to keep things WSS-y. So I created a document library in my site, and then created a web part page in that doc lib. The problem was that (and I hate this) I couldn't figure out which parts of the API represent these UI's. I started wandering down the path of inspecting the content type of the doc lib, then crafting a list item to match it, but I didn't see how to "use" an ASPX page as a list item.

My head started to hurt, so I backed off. Besides, I prefer to put my web parts on the home pages (Default.aspx) so that I get all the default navigation functionality. In fact, as I realized at this point on my journey, what I really wanted to do was take the default layout on a site's home page, and crush the right zone.

Of course, as another option here, you can do whatever you want with SharePoint Designer, but I want to automate the deployment of my web parts via feature activations. Besides, I feel that Designer is best used only after 5:45 AM when you have a presentation at 9:00 that morning and absolutely nothing else is working.

The answer, or at least the correct path to the answer, came to me last night at AliveOne. I was talking to my friend Jenna, fixated more on her gorgeous hair than her story. "Inside out!" It suddenly hit me. "Don't attack it from the page level, but rather from the web parts within." I needed to write some code in a web part that sacrificed itself by going up to its web part zone and kamikazeing it! I then ran off from Jenna, got a pen from the bar, and scribbled the pseudo code used in this blog on the back of a DJ flyer.

Why I'm thinking about SharePoint in bars, unfortunately, is beyond me.

So how do you programmatically manipulate a web part page in SharePoint from a web part itself? Well with the SPLimitedWebPartManager, and it's fully-loaded cousin, the SPWebPartManager. All you need to know is a URL to get a reference to that page's SPLimitedWebPartManager. Once instantiated, you have methods to add, remove, and modify web parts to or from the zones of the page.

Check out a post of mine for some sample code of this. Almost all of my web parts nowadays are SmartParts, so the above is a good prerequisite article to this one.

One of the "limited" features (as the name implies) is that you do not have access to the Zones collection from this object, so the operations are pretty much limited to web part management. However, if you have a full blown manager, you can do a lot more. The tricky part is getting a reference to one of these puppies.

The only way I've been able to do this is to enumerate up the control tree until I find one. So if I have a user control living in a SmartPart, then, interestingly enough, this.Parent is the SmartPart, and this.Parent.Parent is an SPWebPartManager. With this, it appears as though we have programmatic access to the web part zone as if it were a WebControl!

Unfortunately, beyond changing default fonts and other styles, it didn't prove to be useful. The following code did not hide the zone like I hoped (executed during page load of my user control):

Code Listing 1

  1. using System.Drawing;
  2. using System.Web.UI.WebControls;
  3. using Microsoft.SharePoint.WebPartPages;
  4. using System.Web.UI.WebControls.WebParts;
  5. ...
  6. //get the web part zone id. reflection is used because i was having massive problems casting between smartparts and AJAX smartparts
  7. //for some reason, the types were not matching, probably due to XML type serialization
  8. string zoneID = ((WebPartZoneBase)this.Parent.GetType().GetProperty("Zone").GetValue(this.Parent, null)).ID;
  9. //get the manager
  10. SPWebPartManager mgr = this.Parent.Parent as SPWebPartManager;
  11. //get the zone
  12. WebParts.WebPartZoneBase zone = mgr.Zones[zoneID];
  13. //DOESN'T WORK!
  14. zone.Style.Add("display", "none");
  15. //DOESN'T WORK!
  16. zone.Width = new Unit(0, UnitType.Pixel);
  17. zone.Height = new Unit(0, UnitType.Pixel);
  18. //DOESN'T WORK!
  19. zone.Visible = false;
  20. //but don't worry, we can change the backgound color...ugh...
  21. zone.BackColor = Color.BurlyWood;

I spent a lot of time hacking around here; I was sure this was the way to go! Why expose a web control to us, but not allow any of the rendering attribution work? Who knows. So I next launched a page in my dev portal, and did a "View Source." This is always the first step of a hack, I know, but I was very depressed that the "right way" left us so close to the solution.

I finally found that the web part zone was really just a cell in a table. The default.aspx ghosted page has such a table with one row with three cells; the first has a hard-coded width of 70%, the last 30%, and the middle just a to keep the other two prettily in line. I decided that it was time to hack.

And that meant JavaScript. All I had to do was get my little hands on that row. I would then give the first cell a width of 100%, and hide the rest. Now this is going to be some ugly-ass JavaScript, so I need to lay down some ground rules as to when it'll work:

  • On a ghosted, out-of-the-box default.aspx; the home page of a new site or sub-site (an SPWeb).
  • It works on any page layout in which the zones are in a horizontal line (ie, in the same row)
  • It needs to be placed in an AJAXSmartPart, so that the page load JavaScript fires.
  • It can't be in the left zone.

This code and everything else is up on CodePlex.

Once you dump this into a zone and leave edit mode, the left zone will stretch across the page, and all other web parts as well as their zones will be hidden. Why hide the web parts also? Because, using the AJAX JavaScript page load method, the content will flicker before it is hidden, which is lame. But since the page load of the managed code fires first, we can hide the content that would flicker before its zone is hidden.

That's it! Download the user control from CodePlex via the link above. I plan to add some more web part page / zone management tools that seem to be missing from SharePoint's API, so stay tuned!

No Tags

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.