A Better Enhanced SharePoint 2010 Floating Ribbon

38

Category : SharePoint 2010, SharePoint Ribbon, featured

SharePoint 2010 has issues with its scrolling because of the way it implemented the fixed ribbon. Before we look into these issues (and a workaround) let’s first try to understand what SharePoint is doing. Basically, in order to keep the ribbon fixed at the top of the page, SharePoint put’s the scroll bar on the div tag directly below the ribbon (i.e.: s4-workspace) and removes the “normal” scrollbar for webpages (i.e.: the one that is on the body tag). In order to put the scroll bar on the s4-workspace, they set the overflow property of that div tag. But, in order for an overflow property to work, the height and width must be set appropriately. So, SharePoint also runs javascript on the page load to set the height and width appropriately on the s4-workspace div tag.

The issues noted in this blog are particularly bad on Internet facing sites with SharePoint 2010. They are not that big of deal with Intranet sites. So, I’ve found myself using the techniques in this blog on Internet facing sites and not Intranets. These techniques will work for Intranets, but I don’t like to mess too much with a COTS product when I can help it. I can only hope Microsoft fixes this big issue one day.

SP Ribbon Positioning Issues

  1. IPad and mobile browser use: The reason IPads don’t scroll in SharePoint 2010 is because of how they interact with overflow div tags. Scrolling will work on the IPad if you use the “two-finger” technique. But, nobody will know this is a div instead of a main scroll because SharePoint makes this scroll look like the main scroll. Thus, to the normal user, it just looks like scrolling doesn’t work on your webpage.
  2. Anchor tags: Anchor tagging to sections of the page didn’t work. If you have one page www.mywebsite.com?#bottom that links to another page and the section it is linking too is below the scroll area, you get stuck there. It looks really unprofessional when this happens.
  3. Javascript reliance: A core function of a website should not be reliant on javascript (i.e.: the scrollbars).This can produce multiple issues:
    1. Broken javascript: If any other javascript breaks on the page then the entire site won’t scroll anymore. That is one main reason you don’t make a core function of a page rely on javascript. It is hard to control the other javascript on the page and you can get yourself into bad situations over time with these types of techniques.
    2. Slow loading javascript: You have to wait until all the javascript loads on the page before you can begin scrolling. This is really annoying sometimes.

Microsoft has addressed how to disable this ribbon behavior: http://blogs.msdn.com/b/sharepoint/archive/2010/04/06/customizing-ribbon-positioning-in-sharepoint-2010-master-pages.aspx

Microsoft is basically saying, you can turn this on or turn this off. So, for public facing sites, you will probably want to turn this off. However, this means you content editors won’t get the ribbon pinned to the top of the page. This will make editing content in SharePoint very, very hard.

In my opinion, the fixed ribbon positioning system in SharePoint is a really good idea. But, the “unconventional” implementation causes too many issues with scrolling. I think Microsoft could have implemented this better. Specifically, Microsoft could use the “conventional” fixed position style in css instead of this “unconventional” technique of using overflow div tags. Let me be clear: I don’t think overflow div tags are unconventional. I just think it is unconventional to use that as the main scrollbar on a page.

Solution

Turn off the ribbon positioning system that SharePoint provides and build your own one with fixed position css styles. The steps are actually pretty simple:

Steps

  1. Remove the “scroll=no” attribute from the Body tag
    Note: At this point most people would tell you to remove the s4-workspace tag from your html. In fact, that is what the Microsoft blog mentioned earlier. However, that causes side affects. The gantt chart of task views will stop working, IE7 popups will stop working and anything else that relied on the s4-workspace to be there will stop working. Thus, I do not recommend removing the s4-workspace tag from the html of SharePoint. Instead follow these steps:
  2. Add the following javascript in a script block or an attached javascript file:
    
    //set top padding of the workspace to the height of the ribbon
    function setTopPadding() {
       var wrkElem = document.getElementById('s4-workspace');
       var ribHeight = document.getElementById('s4-ribbonrow').offsetHeight;
       if (window.location.search.match("[?&]IsDlg=1")) {
          //margin works better for dialogs b/c of scrollbars
          wrkElem.style.marginTop = ribHeight + 'px';
          wrkElem.style.paddingTop = '0px';
       }
       else {
         //padding works better for the main window
         wrkElem.style.paddingTop = ribHeight + 'px';
       }
    }
    
    // bind top padding reset to ribbon resize event so that the page always lays out correctly.
    ExecuteOrDelayUntilScriptLoaded(function () { SP.UI.Workspace.add_resized(setTopPadding); }, "init.js");
    

    The above script sets a top padding for our workspace element equal to the ribbon height. This is needed because our new ribbon will be css fixed and that is more of a floating technique. Thus, padding is needed so it doesn’t hang over our workspace.

  3. Add the following css:
    
    body, body.v4.master {overflow:visible !important; height: inherit; width: inherit; }
    
    body #s4-workspace {overflow:visible !important; padding-top:44px;}
    
    /*This sets up our Ribbon for a fixed position. */
    body #s4-ribbonrow{ position: fixed;top:0px;z-index:1000;width: 100%;}
    * html #s4-ribbonrow {position:absolute;} 
    
    /* Set the ribbon popups to be fixed position also */
    #s4-ribbonrow .ms-MenuUIPopupBody, #s4-ribbonrow .ms-popoutMenu, .ms-cui-menu[id ^= "Ribbon."], .ms-cui-tooltip {
    position: fixed !important;
    }
    * html #s4-ribbonrow .ms-MenuUIPopupBody, * html #s4-ribbonrow .ms-popoutMenu, * html .ms-cui-menu[id ^= "Ribbon."], * html .ms-cui-tooltip {
    position: absolute !important;
    }
    
    /*Make sure there are no scroll bars on our popup overlays*/
    .ms-dlgOverlay {width: 100% !important }
    

    Note: I used the star hack above for ie6 (ie6 doesn’t recognize fixed positions correctly and absolute must be used instead). I don’t recommend the star hack (it was for blog purposes only). Please use a seperate ie6 file for ie6 specific css.

That’s it! Now you have a fixed css taking care of keeping the Ribbon on top. Why is this better you ask? The SharePoint’s solution uses javascript to create the scroll area. This means javascript is responsible for whether the site functions or not. My solution uses a fixed css property and only uses javascript to fix the height of the ribbon. Even if javascript is turned off, my solution will work. In addition, my page will work for the public view on all browser types (including IPads).

I started off writing this blog using techniques I thought of. However, I ran across two issues that were problematic. One of the issues had to deal with popus/overlays and other issue dealt with the padding at the top after the ribbon was “fixed”. So, like any good developer, I turned to Google. Thus, I have to give credit to 2 blogs that solve the same issues. In fact, both of these blogs seemed to have taken the same approach I did to this problem. Thus, I used techniques from each blog to come to a solution I feel is the best of all worlds.

The first blog that helped in this solution was: http://www.webpoint0.com/blog/fixed-width-layouts-scrollbar-ribbon-sharepoint-2010/. This blog showed me how to set the top padding of the ribbon in the most elegant way. However, the fix for the popups was not the best on this blog.

The second blog that helped in this solution was: http://kyleschaeffer.com/sharepoint/sharepoint-2010-scrolling/. This blog showed me how to deal with the popups and the popup overlays. However, the fix for the top padding of the ribbon was not as elegant as the first blog.

Once again, thank you so much to the blogs above. Their techniques along with the techniques I had already figured out created a great solution to this common problem.

Issues

Of course, with any solution that changes the core way a system works, there is bound to be issues. We’ve worked through the most common issues in the approach above, but I am confident we haven’t figured out all the issues. So, as issues come up I will post them here so people understand the trade-offs (and maybe come up with solutions for me).

Issue #1: Calendar hovers and add new

When you hover over a day in the SharePoint calendar the “add new” link comes up. This isn’t working “exactly” right in our solution. The reason is, if you scroll down on the page and then hover over a calendar item, the “add new” link shows up in the wrong calendar day. It works perfectly fine if you don’t have to scroll down (the issue only happens when you scroll). I debugged through the javascript and I found the problem. The core.js file of SharePoint has a function called MenuHtc_GetElementPosition. This function recursively loops through the elements of the html and gets the elements position with it’s scroll position to get the x and y axis of the element. However, it never takes into account the documents scroll position. This kind of makes sense because Microsoft doesn’t use the documents scroll position because it overflows the s4-workspace to do scrolls normally. However, we overrode that behavior and went back to the normal scrolling behavior of browsers. I hoped Microsoft would have realized that people would want to do this, but this is one of those functions where the SharePoint code is a little short sighted.

Experimental Solution: This solution overrides the MenuHtc_GetElementPosition function by creating a customcore.js file that gets called after the core.js file. I left the method exactly the same except for one small change. I subtracted the document.documentElement.scrollLeft from the x axis and document.documentElement.scrollTop from the y axis. This should account for our scrolling now.

Note: Microsoft should consider putting this change into their function in the core.js in the next service pack. It wouldn’t affect their “normal” technique for ribbon scrolling and it would help people that are building custom internet sites on SharePoint. I can’t think of a reason they wouldn’t add this into the product. So, if anyone from the Microsoft SharePoint product team reads this, please consider adding this in the next service pack.

  1. Create a javascript file called customcore.js and put the following javascript in it:
    
    function MenuHtc_GetElementPosition(element, relativeToElement)
    {
    	var result=new Object();
    	result.x=0;
    	result.y=0;
    	result.width=0;
    	result.height=0;
    	if (element.offsetParent) {
    		var parent=element;
    		while (parent !=null &&
    			parent !=relativeToElement)
    		{
    			result.x+=parent.offsetLeft;
    			result.y+=parent.offsetTop;
    			AdjustScrollPosition(parent, relativeToElement, result);
    			var parentTagName=parent.tagName.toLowerCase();
    			if (parentTagName !="body" &&
    				parentTagName !="html" &&
    				parent.clientTop !=null &&
    				parent.clientLeft !=null &&
    				parent !=element) {
    				result.x+=parent.clientLeft;
    				result.y+=parent.clientTop;
    			}
    			parent=parent.offsetParent;
    		}
    
            //This is the custom code added to account for scrolling
            //when the code has been customized to not use
            //overflows in the s4-workspace
    		result.x -= document.documentElement.scrollLeft;
    		result.y -= document.documentElement.scrollTop;
    	}
    	else if (element.offsetLeft || element.offsetTop) {
    		result.x=element.offsetLeft;
    		result.y=element.offsetTop;
    	}
    	else {
    		if (element.x) {
    			result.x=element.x;
    		}
    		if (element.y) {
    			result.y=element.y;
    		}
    	}
    	if (element.offsetWidth && element.offsetHeight) {
    		result.width=element.offsetWidth;
    		result.height=element.offsetHeight;
    	}
    	else if (element.style && element.style.pixelWidth && element.style.pixelHeight) {
    		result.width=element.style.pixelWidth;
    		result.height=element.style.pixelHeight;
    	}
    	return result;
    }
    

  2. Save the above solution in 14 hive layouts folder under your language – ex: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\1033

    In addition, save the same file as customcore.debug.js and put it in the same place (Note: if you want a minimum file you can minimize the customcore.js and leave this one around for the debug file)

  3. Replace the reference to core.js
    
    <SharePoint:ScriptLink language="javascript" name="core.js" OnDemand="true" runat="server" />
    


    with this:

    
    <SharePoint:ScriptLink language="javascript" name="core.js" Defer="true" runat="server"/>
    <SharePoint:ScriptLink language="javascript" name="customcore.js" Defer="true" runat="server"/>
    

Tips and Tricks for setting up a SharePoint 2010 development environment

Category : SharePoint 2010, featured

While SharePoint 2010 is similar to SharePoint 2007, there are many tips and tricks to setting up a proper SharePoint 2010 development environment. Some of these are the same as SharePoint 2007 and some are new to SharePoint 2010. I run all my development environments in a single server farm configuration on VMWare products.

  1. Use a 64-bit Windows Server environment as your virtual machine because SharePoint 2010 only runs on 64 bit. I am using Windows Server 2008 R2 at the time of this blog.
  2. Make sure your host machine has at least 8GB of RAM. SharePoint 2010 is a beast and you need to allocate at least 5GB to the SharePoint virtual machine (but hopefully you can do more than that). Otherwise it might be slow development for you.
  3. Make sure you host machine has a fast disk. 7200 RPM will work, but 10000 RPM or an SSD drive will make things go faster for you.
  4. Configure your SharePoint virtual machine to act more like a desktop operating system. SharePoint runs on a server which can make the environment act differently than a desktop operating system. I use the Windows 2008 Workstation converter from: http://www.win2008workstation.com/win2008/windows-server-2008-workstation-converter. This allows me to:
    1. Remove the Shutdown tracker
    2. Change the machine name
    3. Disable Enhanced IE Security Configuration
    4. Install Desktop Experience
    5. Disable Verbose messages at startup and shutdown
  5. Install SQL Server 2008 SP1 and the cummulative updates. At the time of writing this blog the latest cummulative updates were required to install SharePoint 2010.
  6. Turn the machine into an Active Directory Domain Controller
  7. Create an sp_admin account in my AD and use this account to setup SharePoint
    1. Give this account DBCreator and Security roles in the SQL Server database
    2. Delegate Replicating directory changes control to this user (this is used in lieu of making the user an administrator on the machine)
      1. In AD Users and Computers applet, right-click your domain and choose delgate control
      2. Choose “Create Custom Task to Deletage”
      3. Choose to delegate control of “This folder, existing objects in this folder”
      4. Choose to pick “Replicating Directory Changes”
  8. Setup environment variables to the 14 hive
  9. Setup a menu on the toolbar to the 14 hive so you have easy access to it on your server
  10. Enable developer dashboard on demand: stsadm -o setproperty -pn developer-dashboard -pv OnDemand
  11. Enable Sandbox Solutions to work on a Domain Controller (typically they don’t). Use the following PowerShell script:

$acl = Get-Acl HKLM:\System\CurrentControlSet\Control\ComputerName
$person = [System.Security.Principal.NTAccount]“Users”
$access = [System.Security.AccessControl.RegistryRights]::FullControl
$inheritance = [System.Security.AccessControl.InheritanceFlags]“ContainerInherit,ObjectInherit”
$propagation = [System.Security.AccessControl.PropagationFlags]::None
$type = [System.Security.AccessControl.AccessControlType]::Allow
$rule = New-Object System.Security.AccessControl.RegistryAccessRule($person, $access,$inheritance, $propagation, $type)
$acl.AddAccessRule($rule)
Set-Acl HKLM:\System\CurrentControlSet\Control\ComputerName $acl

Developing SharePoint WebParts using User Controls and Web Applications

100

Category : featured, sharepoint, webpart, wspbuilder

If you’ve read my blogs before, then you probably know I am a fan of WSPBuilder (http://www.codeplex.com/wspbuilder). I like the intuitive nature and flexibility of the product. It really helps with the deployment aspects of SharePoint features and functionality. However, in the end, it is really just a structured way to create a deployment/feature project that will create the wsp install file for SharePoint. It really doesn’t help much when building UI functionality. For example: if you want to build a Web Part in SharePoint, you still have to build the Web Part code out programmatically (instead of using the WYSIWYG features of Visual Studio). The same issue comes up with building master pages, application pages or anything that requires html and a code behind.

In this article I am going to show you how you can utilize the flexible nature of WSPBuilder, ASP.Net Web Applications and post build scripts in order to utilize WSPBuilder as your deployment project for your UI. 

Solution Overview

SharePoint is a dynamically generated website that pulls information out of a database. It also utilizes files on the server and uses those files as templates or actionable files. The combination of these static files on the server and the information in the database creates the web page we see. This architecture is what allows us to create pages, add webparts, modify navigation, etc… all within the SharePoint site itself.

So, when developing against SharePoint, we need to deploy files to this static place on the server and register the files in the database. This static place on the server is called the 12 hive. It is usually found at: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12. A lot of stuff goes on in the 12 hive. You have the templates for the website, images, themes, etc… You also have very special items called Features. Features allow us to deploy custom functions to SharePoint and then activate/deactivate them at our leisure.

WSPBuilder allows us to “mimic” the 12 hive, within a Visual Studio project. As long as you have the same 12 hive structure setup, it can create the SharePoint deployment file (i.e.: the wsp). You do not need WSPBuilder to create wsp files; you can do the same thing by building extra files in your solution called manifest.xml and ddf files. However, for rapid application development, it is easier to use a third party solution like WSPBuilder because it creates those extra deployment files for you.

While WSPBuilder is a great tool to help us build the deployment files, it is not a web application project in Visual Studio. Web application projects help us build code behind and designer files for our server side controls.

Thus, the ideal solution for building UI elements in SharePoint consists of:

  1. ASP.Net Web Application project to build the UI elements
  2. WSPBuilder project to create our deployable wsp file

The ASP.Net Web Application project will contain the UI elements (such as User Controls). The build process will move the appropriate elements from the ASP.Net Web Application project to the WSPBuilder deployment project. Then the deploy will move the files from the wsp to the SharePoint Server.

Deploy

The key to this solution is seperation of concerns. You should build all UI related functionality in the ASP.Net Web Application project. All SharePoint specific functionality (ex: features), should be built in the WSPBuilder project.

 

Create the WSPBuilder deployment project

  1. Create your project in Visual Studio (File – New – Project)
    • Choose the WSPBuilder project. I am utilizing the one under c# for this example.
    • Give it a good name. I am using DemoProject for this example.
    • Make sure it creates a new solution when creating the project.
  2. Add a folder under the 12 folder called “Template”.
  3. Add a folder under the Template folder called “LAYOUTS”.
  4. Add a folder under the Template folder called “FEATURES”.
  5. Add a folder under the Template folder called “CONTROLTEMPLATES”.
  6. Add a folder under the project called “GAC”.

Note: The “GAC” folder in WSPBuilder is a special folder. We can place external dlls in this folder the the resulting WSP will deploy those dlls to the GAC for us.

DemoProject

 

Create the UI project

As I mentioned in the beginning of this article, the point is to create our UI elements in an ASP.Net Web Application project. So, we need to create another project, in the same solution, so that we can develop our UI elements.

  1. Create the UI project (File – Add – New Project)
    • Choose the ASP.NET Web Application Template. I am utilizing the one under c# for this example.
    • Give it a good name. I am using DemoProjectUI for this example.
  2. Delete the Default.aspx
  3. Sign the project (this is because we are going to deploy to the GAC)
    • Go to the properties (right-click the project and choose properties).
    • Go to the Signing tab.
    • Choose “Sign the assembly”.
    • Under the “Choose a strong name key file” – choose <New>
      • Give it a strong name – I usually use the name of my project (for example: DemoProjectUI).
      • Uncheck “Protect my key with a password”.
  4. Add in the post build commands
    • Go to the properties (right-click the project and choose properties).
    • Go to the Build Events tab.
    • Add the following into the post build section:
      xcopy "$(TargetPath)" "$(SolutionDir)DemoProject\GAC\" /Y /s
      xcopy "$(ProjectDir)*.ascx" "$(SolutionDir)DemoProject\12\TEMPLATE\CONTROLTEMPLATES\" /s /Y /R

Let’s recap what we did in the steps above. First we created a WSPBuilder project called DemoProject. This is our deployment project. It will create wsp files that we can deploy to SharePoint. Then we created an ASP.Net Web Application project called DemoProjectUI. This is where we will create all our UI elements. This will allow us to create user controls with html and code behind files. Lastly, we made sure that we moved the dll and ascx files, from the DemoProjectUI project, to the appropriate place in the DemoProject project.

 

Create a Web Part

Our next step is to create a Web Part. As anyone who has developed in SharePoint before knows, Web Parts are complete code files. They are not the html with code behind files we are used to when developing in ASP.Net. Some people are fine with developing Web Parts completely programmatically. However, it is much easier to create UI elements when you have WYSIWYG editors, html and code behind.

One way to get the normal ASP.Net web development experience, when developing Web Parts, is to use the SmartPart. The SmartPart is a very clever Web Part, developed by Jan Tielens, which can render .Net user controls in Web Parts. I really like the SmartPart, especially for people learning to build SharePoint Web Parts as user controls. However, I like more control over what I do and there are some limitations to the SmartPart. It is not my intent to go over those limitations in this article, but you can read them here: http://weblogs.asp.net/erobillard/archive/2008/03/04/what-to-know-about-smartpart-and-loadcontrol.aspx

In the end, you can accomplish the same thing as the SmartPart using the “LoadControl” method in .Net. Thus, this article will show how to create a Web Part, which will load the user control from our UI project.

  1. Create the Web Part using WSPBuilder
    • Right-click on the DemoProject project
    • Go to Add – New Item
    • Choose WSPBuilder – Web Part Feature
    • Give it a good name. For this example I am going to use DemoFeature
    • A popup will come up with Title, Description and Scope. Since we are developing a Web Part, you must choose “Site” for the scope. This is because we need the Web Part to deploy to the Web Part gallery of our Site Collection.

    Notice that WSPBuilder did two things for you:
    - It created the feature in the features folder
    - It created the Web Part code in a folder called WebPartCode

  2. Modify the Web Part code to use “LoadControl”
    • Open up the DemoFeature.cs file in the WebPartCode folder
    • Remove the MyProperty property and attribute for now. This is just WSPBuilder showing you how you can use properties. We aren’t going to use them for this demo.
    • Find the CreateChildControls method and find the comment that says “Your code here…”
      • Remove the line under it.
      • Replace it with this: this.Controls.Add(Page.LoadControl("~/_controltemplates/DemoControl.ascx"));

      Your CreateChildControls method should look like this:
      protected override void CreateChildControls()
      {
          if (!_error)
          {
             try
             {
                base.CreateChildControls();
                this.Controls.Add(Page.LoadControl("~/_controltemplates/DemoControl.ascx"));
             }
             catch (Exception ex)
             {
               HandleException(ex);
             }
          }
      }

  3. Add the control to the UI project
    • Right-click on the DemoProjectUI project
    • Go to Add – New Item
    • Choose Web – Web User Control
    • Give it a good name. For this example I am going to use DemoControl.ascx

Now, when you build your solution, the DemoControl.ascx will move to the ControlTemplates folder in the DemoProject project. The SharePoint Web Part will look for the control by using the _controltemplates path.

Note: SharePoint can find any control in the ControlTemplates folder by using the _controltemplates path because of a mapping it creates in IIS. SharePoint maps the _controltemplates path to the servers 12 hive at 12/Template/ControlTemplates.

 

Utilizing the Code Behind

We now have our basic solution setup. We have our UI project and can build our user control there. We have our WSPBuilder deployment project that will create our SharePoint install file. But, we aren’t ready to deploy just yet. We still need to tell our user control how to talk to its code behind. Because we are utilizing the GAC for our assemblies, we need to put a fully qualified domain in our ascx file. There are a couple of techniques for figuring out this fully qualified domain. What I like to do is deploy the project and go to the GAC to get the properties.

  1. Deploy the WSP, so that the assembly gets added to the GAC, so that we can pull out the assembly information.
    • Right-click on the DemoProject project
    • Click WSPBuilder – Build WSP (wait for it to finish)
    • Right-click on the DemoProject project
    • Click WSPBuilder – Deploy WSP (wait for it to finish)
    • Get the assembly information from the GAC
      • Usually found at C:\Windows\assembly
      • Right-click on the DemoProjectUI assembly and click properties
      • Note the public key token and version ( I suggest copying the public key token at this point because we are going to use this information in the next step).
  2. Add the assembly information to the ascx
    • Go to the DemoControl.ascx file in the DemoProjectUI project
    • Add an Assembly reference as the first line in this file. Below is an example. However, you cannot copy this example. Your assembly reference must have the correct information about your assembly (including your public key information).


<%@ Assembly Name="DemoProjectUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=772ab5f02712b819"%>

 Now we are ready to test our solution!

 

Deploy the Solution

Now that we are finished setting everything up, we can deploy the solution. This is real easy with the use of WSPBuilder as long as we are developing on a SharePoint server.

Note: Please make sure you have a web application and site collection setup in SharePoint before doing the following steps. When you deploy the WSP solution, it will deploy to all web applications on your development server. Thus, the web application must exist before you deploy.

  1. Right-click the DemoProject project
  2. Click WSPBuilder – Build WSP (wait for it to finish)
  3. Right-click on the DemoProject project
  4. Click WSPBuilder – Deploy WSP (wait for it to finish)
  5. Open up your SharePoint site.
  6. Note: if you go to the SharePoint site at this point and it says “Server Not Available”, then just keep refreshing the page until it shows up. The WSP install recycled the application pools because it needs to every time a dll in the GAC is added or modified. It sometimes takes a few seconds for this process to finish.

  7. Go to Site Actions – Site Settings
  8. Go to Site Collection Features
  9. Activate the DemoFeature
  10. Go back to the site
  11. Go to Site Actions – Edit Page
  12. Click “Add a Web Part” in one of your web zones
  13. Find your WebPart. It should be under “MyGroup” unless you changed the group name in your feature. The elements.xml file in the feature folder of the DemoProject lets you configure this information. I
  14. Add your Web Part to the page

At this point your Web Part is empty because we didn’t add any html or code to it. However, you solutions architecture is ready to go. Now you can go back to your User Control, do your development, deploy the solution and it will show up on your page. Let’s give it a try.

  1. Go to the DemoProjectUI project
  2. Open the DemoControl.ascx
  3. Put a label tag on the control
  4. <asp:Label runat="server"  ID="test" />

  5. Go to the code behind (i.e.: DemoControl.ascx.cs)
  6. In the Page_Load type the following
    protected void Page_Load(object sender, EventArgs e)
     {
          test.Text = "Hello World";
     }
  7. Right-click the DemoProject project
  8. Click WSPBuilder – Build WSP (wait for it to finish)
  9. Right-click on the DemoProject project
  10. Click WSPBuilder – Deploy WSP (wait for it to finish)
  11. Open your SharePoint site and see your Web Part. It should say “Hello World”.

Remember: if it says “Server Not Available”, then keep refreshing the page until the site shows up again.

Wow, that was a lot of setup just to create a user control that can render in a Web Part. But, the great thing is, you only have to do the setup once. As a SharePoint Architect, I set this up for my team and they can just concentrate on building the user controls. It runs very smooth!

Per popular demand, here is the demo solution from the walkthrough. I used Visual Studio 2008, WSPBuilder Extenstions 1.0.5 and .net 2.0 for this solution (I used 2.0 so it can work for a client of mine, it can be upgraded to 3.5 easily)
DemoProject

Cleaning up your WebPart Gallery

19

Category : featured, sharepoint, webpart

Deploying webparts in SharePoint can be difficult (when you are learning) because of the many ways to do it. You can manually add webparts to the WebPart gallery, you can add WebParts through features and you can even manually add them to certain file system folders.

If you have developed extensively in SharePoint, you probably choose the feature way to deploy WebParts. I am not going to go into this conversation right now, but it is well known that the best practice for building webparts is to deploy them with features. However, one thing that nobody really talks about is removing the WebPart from the WebPart Gallery. If a WebPart is placed in the WebPart gallery when the feature is activated, shouldn’t it be removed from the WebPart gallery when the feature is de-activated? In fact, this is essential in keeping your gallery clean and in eliminating future issues with assembly versioning. The problem is that many developers, who might be extremely experienced in SharePoint and frequently use it to deploy WebParts via the latest Mobile Broadband, simply don’t think to deactivate them. However, this is an important step in using a WebPart gallery. In this article we are going to go over the basics of how WebParts are added to the WebPart gallery during activation of the feature and then we are going to show how you can clean up your gallery when the feature is deactivated.

Overview of WebParts and Features

The premise of WebParts is simple – you are adding an xml file to a special list in SharePoint. This special list is called the Web Part Gallery and the xml file you add is called a .webpart file or a .dwp file. The .webpart or .dwp file “describes” the properties of the WebPart and points to a code file where the .net code runs that builds the WebPart controls. If you want to visit this special WebPart Gallery you can go to your SharePoint site and put “/_catalogs/wp” after your url (i.e.: http://server:port/_catalogs/wp). If I have already confused you at this point, you probably want to start looking into some beginner guides to WebParts in SharePoint. I will do a small overview of WebParts in this article (that might be helpful for beginners), but the point of this article is to show some advanced techniques to how to clean up your WebPart Gallery.

When deploying webparts in SharePoint I always use a Feature to deploy the WebPart to the WebPart gallery. Then I always wrap these features up in a WSP solution in order to deploy a single solution to my SharePoint farm. This is best practice and is really easy once you have done it a couple of times. Personally, I choose to use WSPBuilder to build my WSP solutions (but the process is the same if you use Visual Studio Extensions or if you build your WSPs manually).

If you are using WSPBuilder you can just click Add – New Item – WSPBuilder – WebPart Feature. This will create a .webpart file, feature.xml, element.xml  and code file for you. And, I choose “Site” scope so that the WebPart is added to my Site Collection WebPart Gallery. If you don’t use WSPBuilder, the process is the same, you still have to build the .webpart file, feature.xml, element file and code file (WSPBuilder just does it for you).

So, let’s talk about what these files do:

1.       Feature.xml – this file defines “how” the feature will get deployed and the general settings for the feature. Technically, this is the only file required for a feature to work.

 

The important part of this file is the “Scope”. The scope defines where the feature will be deployed (Site, Web, Web Application, Farm). For webparts, we usually choose “Site” in order for the WebPart to be added to the WebPart Gallery. The other important part of this file is the “ElementManifest”. This tells the feature where the element file is located. The element file is the actually actionable file in a feature.

<?xml version=1.0 encoding=utf-8?>

<Feature  Id=7801227a-326a-4a65-8769-6e56ade76b66

          Title=Custom Webpart

          Description=This is my custom webpart Webpart

          Version=12.0.0.0

          Hidden=FALSE

          Scope=Site

          DefaultResourceFile=core

          xmlns=http://schemas.microsoft.com/sharepoint/ >

  <ElementManifests>

    <ElementManifest Location=elements.xml/>  

  </ElementManifests>

</Feature>

 

2.       Elements file – usually we call this file elements.xml, but you can call it whatever you want. You just need to make sure it is an xml file and you need to make sure that the name you call it is the same as the reference in the feature.xml.

 

This file tells SharePoint “what” to do with the feature. There are a lot of different things you can do with SharePoint Features. So, you have to do your research to understand the different xml combinations. In the case of the WebPart, we are using a “Module” action. Module actions move files to different galleries (or lists) in SharePoint. With webparts, we want to move the .webpart gallery to the WebPart gallery list. We do this by setting the “url” property to the “_catalogs/wp” path. That is the path for the WebPart gallery list. The other thing to notice in this file is the “Group” and “QuickAddGroups”. These define the grouping when you click “Add New Webpart” on your SharePoint site.

<?xml version=1.0 encoding=utf-8 ?>

<Elements xmlns=http://schemas.microsoft.com/sharepoint/>

  <Module Name=WebPartPopulation Url=_catalogs/wp RootWebOnly=TRUE>  

         <File Url=CustomWebpart.webpart Type=GhostableInLibrary>

                <Property Name=Group Value=RDA></Property>

                <Property Name=QuickAddGroups Value=RDA />

         </File>    

  </Module>

</Elements>

 

3.        .webpart file – this is the file that “describes” the properties of the WebPart. This could also be a .dwp file (it all depends on the version of the WebPart you are using). SharePoint supports .net webparts and SharePoint webparts. That is why you can have .dwp and .webpart files. So, any property you can set in your WebPart, can be set in this file. I am not going to show an example here because the set of properties is different for every WebPart.

 

This file also contains the assembly path to the code file. This is important, because if you ever change information about the Code file (name, version, etc…), then you need to change the path in your .webpart file.

 

4.       Code file – this is the file that actually runs the webpart code. These files inherit from one of two classes depending on the version of WebPart you are building (.net webpart or SharePoint webpart). For example, a .net framework webpart will inherit from Microsoft.SharePoint.WebPartPages.WebPart. Once again, I am not going to show an example of this, because it is different for every customization. The basis of this class is that you build out your html controls programmatically and add them to the Control collection.

 

Side Note: On a side note that is not really part of this article, don’t think the SharePoint webpart (i.e.: dwp) is better to use than the .net webpart (i.e.: .webpart) just because one is labeled a SharePoint webpart. If you don’t plan on using SharePoint webpart connections or part caching, I actually recommend using a .net webpart in SharePoint. Also, you might hear .dwp webparts referred to as Version 2 webparts and .webparts referred to as Version 3 webparts. This is because .dwp webparts were originally built just for SharePoint 2.0 and are backwards compatible. But, in SharePoint 3.0 we got the ability to use the asp.net webparts.

 

Cleaning up your WebPart Gallery

Ok, so you know how to deploy a WebPart to the WebPart Gallery. But, you notice that when you de-activate your Feature the WebPart is still hanging around in the Gallery. Some developers don’t really care about this. But, other than the obvious problem of keeping a clean Gallery for maintaince, there is another big issue. Let’s say you are using versioning for your assembly for the WebPart code. The reference for the assembly is located in the .webpart file. Thus, if you don’t remove the WebPart from the gallery before you make version changes, then your new assembly version will never make it to the gallery.

So, the easiest way to do this is to just go to the WebPart Gallery and remove it before you install and activate your updated feature. However, as most SharePoint developers know, you want to stay away from manual processes as much as possible. That makes your customizations almost impossible to maintain as your code base grows.

But, the answer to this problem is easy. Create a feature receiver to remove the webpart from the WebPart Gallery when the feature deactivates. I saw this done for the first time when I was reviewing the code for the Forms Based Authentication project in the Community Toolkit for SharePoint:  http://www.codeplex.com/CKS. I modified the code a little to meet my needs, but it is basically the same. Here is how you do it.

Create a Generic Class

This class is a generic class that will work for any WebPart feature receiver. The idea behind this class is to implement the Feature Deactivating event and remove the WebPart. Here is the code for this class:

     class GenericWebPartFeatureReceiver : SPFeatureReceiver

    {

 

        /// <summary>

        /// Remove the webpart from the webpart gallery. This is to fix a shortcoming of SharePoint

       ///       that it doesn’t remove

        /// the webpart when the feature gets deactivated (even though it adds it when the feature

       ///       gets activated).

        /// </summary>

        /// <param name=”properties”></param>

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

        {

            SPSite site = null;

            try

            {

                site = properties.Feature.Parent as SPSite;

                using (SPWeb web = site.RootWeb)

                {

                    SPList list = web.Lists["Web Part Gallery"];

 

                    // go through the items in reverse

                    for (int i = list.ItemCount – 1; i >= 0; i–)

                    {

                        // format name to look like a feature name

                        string webpartName = list.Items[i].Name;

                        webpartName = webpartName.Substring(0, webpartName.IndexOf(‘.’));

 

                        // delete web parts that have been added

                        if (properties.Feature.Definition.DisplayName == webpartName)

                        {

                            list.Items[i].Delete();

                            break;

                        }

                    }

                }

            }         

            finally

            {

                if (site != null)

                    site.Dispose();

            }

        }

 

        public override void FeatureActivated(SPFeatureReceiverProperties properties){ }

 

        public override void FeatureInstalled(SPFeatureReceiverProperties properties){ }

 

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }

    }

 

Call Feature Receiver

After your Generic Feature Receiver is built, then you just need to call it from the feature.xml file for all your WebParts. Here is some sample code. It is the same as the feature.xml file I showed above, except for the fact that I placed a reference to a RecieverAssembly and a ReceiverClass.

<?xml version=1.0 encoding=utf-8?>

<Feature  Id=7801227a-326a-4a65-8769-6e56ade76b66

          Title=Custom Webpart

          Description=This is my custom webpart Webpart

          Version=12.0.0.0

          Hidden=FALSE

          Scope=Site

          DefaultResourceFile=core

          xmlns=http://schemas.microsoft.com/sharepoint/

   ReceiverAssembly=MySolution, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3cbe19ecf7353dae

   ReceiverClass=MySolution.GenericWebPartFeatureReceiver>

  <ElementManifests>

    <ElementManifest Location=elements.xml/>  

  </ElementManifests>

</Feature>

Note: You cannot just copy the xml above. The reference to the features ReceiverAssembly and ReceiverClass is specific to my implementation. When you deploy the assembly that contains the “GenericWebPartFeatureReceiver” to your BIN or GAC, then you need to get the information necessary to build out these two lines. Make sure the name of the Assembly and Namespaces match your implementation. And, make sure that the PublicKeyToken matches your public key for your assembly.

 

 

That’s it; you now have a Generic WebPart Feature Receiver that will remove the WebPart from the WebPart Gallery whenever your WebPart Feature is deactivated. This should help you keep your gallery clean and will help eliminate possible issues with assembly versioning.