Thursday, November 6, 2008

DesignModeConsoleContainer vs EditModePanel - What's the Difference?

Maybe you've seen Microsoft.SharePoint.Publishing.WebControls.EditModePanel and the Microsoft.SharePoint.WebControls.DesignModeConsoleContainer as you're building your SharePoint layout pages. Maybe you've even seen one or the other as you're looking through some of the out of the box layout pages. If so (or even if you're just curious), you might find this information a little useful.

I've tried to find the difference between the two on the web, and the information just isn't there (like so many other things SharePoint.) As you can well imagine by the namespaces, the EditModePanel is comes from the Publishing namespace, which means you'll only see it if you're running Microsoft Office SharePoint Server. The other, the DesignModeConsoleContainer is from the WSS area, and comes standard as part of you WSS-enabled server.

As far as functionality goes, they're both designed to allow you to only show things when your page is in Design or Edit mode. This way, you can have some text or fields that you only want someone editing the page to see, but remain hidden from the average user.

Using either control is pretty straight forward: simply open one of the tags, put whatever controls you want inside it, then close the tag.

Examples:

<sharepointwebcontrols:designmodeconsolecontainer runat="server">
   You're in design mode
</sharepointwebcontrols:designmodeconsolecontainer>

or

<publishingwebcontrols:editmodepanel runat="server">
   You're in edit mode
</publishingwebcontrols:editmodepanel>

But, what--if any--is the difference between the two you might ask? Well, the DesignModeConsoleContainer is just a place to display stuff: text, images, special formatting, stuff like that. If you want to put editable fields in there, you need to use the EditModePanel. For some reason, the DesignModeConsoleContainer will seem like it works for fields, but none of the data will save if the user changes it.

For example, if you you want to allow users to fill in metadata for your pages that you don't want displayed on the page (i.e. select a region, assign a popularity rating, expiration date, rollup image, etc), place those fields inside of the EditModePanel. If you just want to display instructions for the person editing the page that will let them know about procedures for publishing a page, terms and conditions for pages or their site, or anything like that, you can put it in either control.

I hope this information saves other developers the time I spent trying to figure this out.
Happy coding!!

Friday, October 24, 2008

Finding closed web parts in pages

Did you know that if you "close" a web part, it doesn't really go away? Instead, it's running invisibly in the background of your page every time the page loads. YIKES!!

Firstly, this seems to me like a horrible waste of system resources. I know from personal experience early on in my SharePoint career that it's really easy to believe that the web parts are gone when you close them. Instead, you must be sure to "delete" the web part so that it is removed from the page.

I've only found one way to locate these closed web parts, and it's not anywhere in the UI. You have to type "?contents=1" into the end of your page address in the web browser. So, for example, if your page's URL was http://localhost/pages/default.aspx, then you would type http://localhost/pages/default.aspx?contents=1.

So, here's my opinion on this--just in case someone from the SharePoint Team runs across this post. If closing a web part is going to keep it running for each page load, then there must be an intuitive way to manage these closed web parts that doesn't require remembering a URL hack. Manipulating querystrings by hand in a web site is actually a form of hacking. Back in the olden-days (yes, I'm dating myself here), inexperienced developers actually didn't safe-guard against users becoming entirely different people by simply changing the "userid" value in a querystring. Granted, typing "contents=1" at the end of your URL is actually pretty harmless, but from a usability stance, why should we have to?

For anyone who doesn't think this is a big deal (first of all, allow me to slap you for your tollerance of wasted system resources and potentially slower load times), consider for a moment what would happen if you closed a bunch of web parts and then uninstalled the web part feature? That's happened to me before. Suddenly, every page on your site with that hidden web part won't load anymore. All you get is an error page. With no navigation at your disposal and no way to see the closed web parts in administration pages, you're really pretty much stuck! This actually happened to me one time. It cost me HOURS of development time just to figure out what was going on!!

When I have time, I'm going to investigate adding a security-trimmed URL to my master pages that will provide Administrators a quick link to see the hidden contents of the current web page. When I get that tag, I'll be sure to share it with you all.

Happy Coding!

Monday, October 20, 2008

Sending Email From a Custom Workflow Activity

When creating custom workflows for your SharePoint server, you may find that you have a need to reuse the same set of activities over and over again. A perfect example of this is when you are using a repeater for an approval task to get approvals from multiple people. Another excellent use for a custom activity is when you are going to have multiple workflows using the same series of activities in a reusable sort of model.

One limitation I've found is that it's impossible to send email from your custom activity. The SendEmail activity requires that you have a reference to your Workflow token, but the activity doesn't have any knowledge of the workflow it's running within. You could use the SendEmail routine of the SPUtility class, but that requires a reference to the SPWeb object, which cannot be stored or passed to a custom activity because it's not serializable.

So, what's a developer to do, you ask...?

Events. It turns out that custom activities can raise events to the workflow which can then execute code at specific times. It's important to note that you cannot run activities in a workflow when an activity's event fires--the workflow is essentially halted, and will remain that way until your custom activity has completed. However, the event handler in your workflow can execute code behind the scenes, which will allow you to send an email with the SPUtility class.

I think it's important to point out that the Workflow Designer doesn't always like events mapping from your custom controls. They'll show up in the activity's properties, but will sometimes have the infamous red error icon indicating that the event could not be found. This shouldn't be a problem, and your DLL should compile just fine regardless of this error.

Also important to know is that your custom activity may not show up if you've already deployed your workflow to your SharePoint server. Sometimes it might also show up by throw an error when you try to drag the activity into your workflow. This is because the old version of the DLL is already in the GAC...and that version doesn't have your new activity in it. Simply deploy your workflow to your SharePoint server, or copy the DLL directly in the GAC and then try adding the activity again. With the custom activity now showing up in the assembly on the server, it should show up in your tool pane.

Good luck, and happy coding!

Setup Batch File To Simplify Feature Deployment

Have you ever wanted to activate or install a feature on your server, but hated working with the STSADM commands? I know I do...so I create a batch file that will automate most of it for you.

To use it, just copy the code below and place it into a file called "setup.bat" (or you can call it something else as long as it has the ".bat" at the end.) Copy this batch file into all of your custom feature folders in your 12 hive (for example, 12\TEMPLATE\FEATURES\MyCustomFeature), then double-click to run it (note: you must be on the server--either logged in directly or remoted in for this to work.)

Internally, the batch file will analyze the folder it's in and use that as the feature that it runs operations against. Since STSADM's operations involving features have the ability to use the folder name instead of the feature name, this gives us a quick way to manipulate features in the 12 hive.

The batch file supports the following operations: install, uninstall, activate, deactivate, repair.

Install - Installs the feature to your SharePoint server. Uses the InstallFeature operation of STSADM
Uninstall - Uninstalls the feature from your SharePoint server. Note: the feature must be deactivated from all webs before uninstall works.
Activate - Activates an installed feature to a web on your server. If the feature is not installed, this command will error. You also must specify the URL of the web you want the feature activated on (for example: http://localhost, http://localhost:81, or http://myWSS)
Deactivate - Deactivates a previously activated feature on a web on your server. If the feature is not activated on the web specified, a message stating such will be displayed. You must specify the web URL that you want to deactivate.
Repair - Use the repair feature when you want to update a feature. It will deactivate, uninstall, reinstall, then reactivate the feature on your server. You must specify the web URL that you want the feature repaired on (If you have the feature activated on multiple web URLs, you must first deactivate the other URLs and then reactivate them after repairing.)

Below is the code for your batch file:

@ECHO OFF
REM -GET THE NAME OF THE FEATURE THAT THE BAT FILE RESIDES IN
echo ===================================================
cd %~dp0
set BatDir=%CD%
REM echo BatDir="%BatDir%"
pushd ..
call set FEATURENAME=%%BatDir:%CD%\=%%
popd
ECHO FEATURE: %FEATURENAME%
echo ===================================================

:SETMODE
SET /p SETUPMODE="SELECT MODE [INSTALL, UNINSTALL, ACTIVATE, DEACTIVATE, REPAIR, EXIT]: "

REM * DETERMINE SETUP MODE BASED ON USER INPUT
IF "%SETUPMODE%"=="INSTALL" (goto INSTALL)
IF "%SETUPMODE%"=="install" (goto INSTALL)
IF "%SETUPMODE%"=="UNINSTALL" (goto UNINSTALL)
IF "%SETUPMODE%"=="uninstall" (goto UNINSTALL)
IF "%SETUPMODE%"=="ACTIVATE" (goto ACTIVATE)
IF "%SETUPMODE%"=="activate" (goto ACTIVATE)
IF "%SETUPMODE%"=="DEACTIVATE" (goto DEACTIVATE)
IF "%SETUPMODE%"=="deactivate" (goto DEACTIVATE)
IF "%SETUPMODE%"=="REPAIR" (goto REPAIR)
IF "%SETUPMODE%"=="repair" (goto REPAIR)
IF "%SETUPMODE%"=="EXIT" (goto EXITBAT)
IF "%SETUPMODE%"=="exit" (goto EXITBAT)
ECHO ERROR: Setup mode "%SETUPMODE%" not recognized. Type "EXIT" to quit.
goto SETMODE

:REPAIR
set /p featureUrl="What url should this feature be activated on? "
ECHO Deactivating feature on %featureUrl%...
stsadm -o deactivatefeature -name %FEATURENAME% -url "%featureUrl%"
ECHO Uninstalling feature...
stsadm -o uninstallfeature -name %FEATURENAME%
ECHO Reinstalling feature...
stsadm -o installfeature -name %FEATURENAME%
ECHO Reactivating feature on %featureUrl% and restarting IIS...
iisreset
stsadm -o activatefeature -name %FEATURENAME% -url "%featureUrl%"
goto FINISHED

:INSTALL
stsadm -o installfeature -name %FEATURENAME%
REM * Add the template STP files
REM stsadm -o addtemplate -filename "ListTemplates/DMXList.stp" -title "DMX List" -description "A base list for DMX-related lists"
iisreset
goto FINISHED

:UNINSTALL
stsadm -o uninstallfeature -name %FEATURENAME%
iisreset
goto FINISHED

:ACTIVATE
set /p featureUrl="What url should this feature be activated on? "
stsadm -o activatefeature -name %FEATURENAME% -url "%featureUrl%"
goto FINISHED

:DEACTIVATE
set /p featureUrl="What url should this feature be deactivated on? "
stsadm -o deactivatefeature -name %FEATURENAME% -url "%featureUrl%"
goto FINISHED

:FINISHED
set featureUrl=
set SETUPMODE=
ECHO FINISHED!
goto SETMODE

:EXITBAT
SET FEATURENAME=


Happy Coding!!! I hope this save you time, too!

Integrating Silverlight With Your SharePoint '07 Server

I've recently been trying to integrate Silverlight 2.0 Beta into my MOSS '07 site. I really like some of the animations that it does, and the polished look just can't be beat! There's been a few times where I wished I could create a Silverlight navigation system, or a products carousel, or other things that are just flashy and cool! The problem is that there's really no way for the Silverlight client (which, remember, is on the visitor's web browser/OS) to be able to communicate with the SharePoint server directly.

I read a post somewhere about your Silverlight application connecting to the SharePoint server's built-in web services. I tried using this approach, but ended up running into security issues when the Silverlight client attempted connecting to the web service. (I still need to come back and investigate this approach a bit more as it seems to be a more robust way of handling the interaction with the server.)

There is, however, a slick little trick to getting it to work. You create your WebPart the same way you would under any other circumstance, then create an instance of the Silverlight class and set it's Source property to the location of the XAP file on your web server. Next, you need to set the control's InitParameters property to "ctlid=SL_DATA" (I'll explain this part later). Then, create a DIV control called "SL_DATA" and add an XML document to it. Finally, you can either add the Silverlight control to your child controls collection or use the Silverlight class's RenderControl function to write the HTML for the control straight to an HtmlTextWriter.

In your Page.xaml.cs file, change your constructor so it takes a string parameter named "controlid". In the body of the constructor, add the following lines of code:




string xmlstring = string.Empty;
if (controlid != null)
{

    HtmlElement ctl = HtmlPage.Document.GetElementById(controlid);
    if (ctl != null)
      xmlstring = (string)ctl.GetProperty("innerHTML");


}


You might be asking yourself what this does for us? It's allows us to grab an XML document from within the HTML generated by the WebPart, which will contain the SharePoint data that only it has access to. Pretty neat huh?

The few samples I've tried have ended up breaking my dropdown menus on my navigation, but if I can master the Silverlight interaction with SharePoint, I'll probably be replacing those anyway with something cool and slick in Silverlight anyway, so it might not be anything to worry about.

Happy Coding!!