Chapter 10. Dynamic interfaces in Web Parts – SharePoint 2010 Web Parts in Action

Chapter 10. Dynamic interfaces in Web Parts

 

This chapter covers

  • Understanding dynamic Web Parts
  • Using JavaScript and jQuery to update the interface
  • Introducing the SharePoint dialog framework
  • Modifying the Ribbon
  • Building context-aware Web Parts

 

Web pages have traditionally been built on the request-response methodology. You send a request for a web page and wait for a response containing the HTML. Each view requires that the server process and render all content, images, and scripts. This static process is slow. In recent years, browser technology has evolved and you can now create web pages that are dynamically and asynchronously updated. The combination of technologies, such as JavaScript, web services, Ajax, XML, and JSON, allows you to update only specific parts of a web page and make the experience more dynamic than ever before.

SharePoint 2010 uses the ASP.NET AJAX framework to build its interface. In this chapter, you’ll take a look at some of the new user interface features that you can leverage in your Web Parts. The chapter begins by showing you how to make your Web Parts more dynamic using the ASP.NET Ajax framework and JavaScript. You’ll also review the jQuery JavaScript library, which allows you to create clean, compact, and cross-browser compliant JavaScript code.

Next, you’ll look at SharePoint-specific features such as the notification messages, the status bar, and the dialog framework. These simple features immediately make your Web Part more dynamic and user friendly.

One of the first things you’ll notice in SharePoint 2010 is the context-aware Ribbon interface. Using XML code and JavaScript, you’ll connect Web Parts to the Ribbon to add new tabs and controls.

10.1. Using Ajax and JavaScript in Web Parts

JavaScript and XML have made the web more accessible and interactive. The combination of these two, called Ajax, is what most people mean when they refer to the technology used to make websites dynamic. Ajax techniques allow you to retrieve information in an asynchronous way. The web page is displayed with placeholders that are asynchronously filled with content, which means the entire page doesn’t have to reload for every single change. The same goes for Web Parts. A Web Part might initially contain a placeholder; after the page is rendered, it can asynchronously request information that fills that placeholder. In this way, you can change a page by updating just a Web Part. This is called a partial update.

 

Note

Ajax (Asynchronous JavaScript and XML) is a combination of browser and web techniques that makes it easy to create dynamic and interactive web applications. By using asynchronous requests on the client that sends JavaScript objects or data to the server, you achieve a dynamic experience. Although XML is in its name, sending XML back and forth isn’t required. A common approach today is to use JavaScript Object Notation (JSON).

 

In ASP.NET, the use of Ajax has been implemented by Microsoft as a set of extensions to ASP.NET called ASP.NET AJAX Extensions. These extensions are used by SharePoint and you can use them in Web Parts to make them dynamic. Building dynamic Web Parts using ASP.NET AJAX Extensions (or in other ways) often requires that you use JavaScript to build the interface. A Web Part can register inline JavaScripts or use JavaScripts in external files.

One of the most popular and commonly used JavaScript libraries is the jQuery library. The jQuery library is often used in SharePoint to accomplish so-called no-code solutions but can also be used in Web Parts development. The use of jQuery simplifies JavaScript programming and at the same time maintains a cross-browser implementation.

10.1.1. Working with Microsoft ASP.NET AJAX Extensions

The Microsoft ASP.NET AJAX Extensions consist of a client framework with JavaScripts and a server framework with a set of controls. These extensions make it easy for ASP.NET developers to enhance their web applications with dynamic interfaces. They use the same techniques and methods that they use in Visual Studio.

To use the extensions in a website, you must install the client and server framework and configure web.config accordingly. In previous versions of SharePoint this process had to be done manually or by using SharePoint Features that modified the web.config file and installed the components on all servers. SharePoint 2010 is based on ASP.NET 3.5, which includes the server and client ASP.NET AJAX framework. The web.config configuration elements are created by default, which makes it easier for you to use the Microsoft ASP.NET AJAX Extensions in any Web Part solution.

The most popular ASP.NET AJAX control is UpdatePanel. This control is similar to the standard Panel control but can be updated asynchronously. The UpdatePanel control has a set of asynchronous triggers that make the update panel reload.

To illustrate, let’s continue to enhance the RSS Web Part that you’ve been building in the last few chapters. Add the button shown in figure 10.1. You’ll use the button to refresh the RSS feed without reloading the entire page.

Figure 10.1. The RSS Web Part has a button that makes a partial update of the page, refreshing only the contents of the specific Web Part.

 

Note

Although I could show you how to do this in a Visual Web Part and use a declarative approach, I recommend using the programmatic approach. Even though you aren’t using a Visual Web Part, this code won’t work as a sandboxed Web Part. The UpdatePanel object requires the ScriptManager, which isn’t accessible from the sandboxed worker process.

 

The first thing that you need to do is declare an UpdatePanel object and a Button in your Web Part class:

protected UpdatePanel updatePanel;
protected Button refreshButton;

These controls are declared in the class as protected so that they can be used in new Web Parts inheriting from this Web Part. The CreateChildControls method is implemented in listing 10.1; the method creates the update panel and the button. The feed isn’t retrieved by this method (as in previous implementations of the RSS Web Part), but instead the feed retrieval is moved to the OnPreRender method.

Listing 10.1. Adding an UpdatePanel to the RSS Web Part

The CreateChildControls method makes the standard check to see if the RssFeedUrl property has a value. If it does, CreateChildControls creates an UpdatePanel object . The button is then added to the control tree. It has no click event defined because you don’t need to execute any specific code if it’s clicked; you just need it to trigger an update. So you connect the button to the update panel using a trigger on the update panel. An AsyncPostBackTrigger is created that takes the control ID of the button as an argument. When the user clicks the button, this trigger will fire and a partial postback will occur. Finally, the UpdatePanel object is added to the control tree. This partial postback will only update the UpdatePanel in the user interface.

To retrieve the feed and also add information about when the feed last was retrieved, you add logic to the OnPreRender method. The implementation, in listing 10.2, looks quite similar to what you just did to render the RSS Web Part—with a few differences.

Listing 10.2. Modifying OnPreRender of the RSS Web Part
protected override void OnPreRender(EventArgs e) {
    XElement feed = XElement.Load(this.RssFeedUrl);

    var items = feed.Descendants("item").Take(this.ItemCount);

    foreach (var item in items) {
        Panel panel = new Panel();
        panel.Controls.Add(new HyperLink() {
            Text = item.Descendants("title").First().Value,
            NavigateUrl = item.Descendants("link").First().Value
        });

        updatePanel.ContentTemplateContainer.Controls.Add(panel);
    }
    updatePanel.ContentTemplateContainer.Controls.Add(
        new LiteralControl("Last updated "));
    updatePanel.ContentTemplateContainer.Controls.Add(
        new LiteralControl(DateTime.Now.ToString()));

    base.OnPreRender(e);
}

The feed is retrieved using the same methods you used earlier but the feed items are added to the ContentTemplateContainer control collection of the UpdatePanel object. This template container is dynamically refreshed in the web interface. Finally, two controls are added so that you can see the time when the feed was last retrieved.

If you now deploy and add the Web Part to a page, it will look like figure 10.1. Click the Refresh button and notice that only the update panel reloads, not the entire page.

The ASP.NET AJAX Extensions can do a whole lot more for your Web Part interfaces. For example, the extensions contain a Timer control that performs postbacks at regular intervals and an UpdateProgress control that shows status information about partial-page updates.

 

Note

The Microsoft Ajax extender controls enhance the client capabilities of standard ASP.NET controls. One common extender control library is the Ajax Control Toolkit, which is a community-supported extension from Microsoft. You can download the Toolkit from http://ajaxcontroltoolkit.codeplex.com/.

 

10.1.2. JavaScripts in Web Parts

JavaScript has evolved; once a web browser feature that made simple calculations or changes to the page, it’s now a service that you can use to take load off the server. Most web applications built today rely heavily on JavaScript, and SharePoint is one of them. The ASP.NET AJAX Extensions use JavaScript to do partial postbacks and updates.

Using JavaScript in Web Parts is a great way to accomplish a dynamic interface that interacts with other items. There are two basic ways to add JavaScript to a Web Part: either using an external JavaScript (.js) file or using inline JavaScripts. Using external JavaScript files is what I recommend. They perform better because you can cache those files. Using inline JavaScript can make programming easier because you can generate the scripts dynamically.

I recommend that you use the ScriptLink control, mentioned in chapter 4, to add external JavaScript files to a Web Part. You can use ScriptLink as a control or add it to the control tree, or you can use one of its static methods to register a script. The following line shows how to register a custom script with a Web Part for the current page:

ScriptLink.Register(this.Page, "Custom.js", false);

The ScriptLink control ensures that the script element is used only once in the output. It also assumes that the JavaScript file is located in the Layouts folder. You can also tell the control to use a localized version of the JavaScript file by setting the third parameter to true.

The ScriptLink control isn’t available in sandboxed solutions. Instead you have to inject the <script> tag manually and point it to a location in SharePoint where the JavaScript file is deployed. You should do this in the RenderContents method of the Web Part, as shown in the following snippet:

protected override void RenderContents(HtmlTextWriter writer) {
    string url = SPContext.Current.Web.Url + "/SiteAssets/script.js";
    writer.Write("<script type='text/javascript' src='"
        + url + "'></script>");
    base.RenderContents(writer);
}

The downside is that the script file will be loaded once for each Web Part instance. To add inline JavaScript code to a Web Part, you should use the ClientScriptManager object of the page. You can insert scripts declaratively in user controls or pages, but ClientScriptManager manages all scripts you add dynamically to the page. To add a script dynamically, you can choose among several methods depending on the situation. Each script has a key and a type that identifies the scripts and avoids duplicates. The ClientScriptManager is accessible from the sandbox, but any scripts registered won’t be transferred from the sandbox.

Use RegisterStartupScript to insert a script that should execute when the page load is complete. A Hello World example of a startup script might look like this:

this.Page.ClientScript.RegisterStartupScript(
    typeof(MyWebPart),
    "helloworld",
    "alert('Hello World');",
    true);

This code will display a JavaScript alert dialog box with the text Hello World once the page is loaded and rendered. The last parameter tells ClientScriptManager that it should enclose the script with script tags. The typeof keyword is used instead of the GetType method of the current object to get the type of the object. This is the preferred approach and avoids double registrations of the scripts when the Web Part is subclassed.

 

Tip

You can avoid loading your JavaScript files multiple times in sandboxed Web Parts by loading them dynamically. One good way to achieve this is by using the SharePoint Script On Demand system, defined in the ECMAScript SP.SOD class. You can find more about it here: http://msdn.microsoft.com/en-us/library/ff410742.aspx.

 

When working with partial postbacks and partial updates, you can’t use ClientScriptManager. The ASP.NET AJAX Extensions have their own script manager, called ScriptManager, to handle the partial updates. ScriptManager is very similar in operation to ClientScriptManager. For instance, if you need to run a script on every partial postback, use the RegisterStartupScript method of ScriptManager instead of the method with the same name of the ClientScriptManager control.

 

Tip

If you’re making your own master pages for SharePoint, include this ScriptManager object to ensure that Web Parts and other controls work as they should.

 

In SharePoint the ScriptManager object is defined in the master page directly after the form tag, which is a requirement for ScriptManager. The definition in the default SharePoint 2010 master page (v4.master) looks like this:

<asp:ScriptManager
    id="ScriptManager"
    runat="server"
    EnablePageMethods="false"
    EnablePartialRendering="true"
    EnableScriptGlobalization="false"
    EnableScriptLocalization="true" />

To get a reference to the ScriptManager from within a Web Part, you use the static method GetCurrent. This method accepts the current page as a parameter and returns the ScriptManager object or a null value as follows:

ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);
if (scriptManager == null) {
    scriptManager = new ScriptManager();
    this.Page.Form.Controls.AddAt(0, scriptManager);
}

The first call is to the GetCurrent method. If ScriptManager isn’t found, GetCurrent creates it and dynamically adds it to the page. Use this approach whenever you’re working with ScriptManager, because it saves you from exceptions in case the designers forgot to add the control to the master page. Notice how ScriptManager is added as the first control of the page’s Form control.

 

Note

The ScriptManager object for the current page can’t be retrieved in a sandboxed Web Part. So, you can’t use the ScriptManager or any dependent controls in a sandboxed Web Part.

 

10.1.3. Working with jQuery

One of the libraries you’ll commonly use when working with JavaScript is the jQuery JavaScript library. jQuery allows you to write little yet effective JavaScript code and there are a great number of plug-ins to jQuery available. jQuery is now officially supported by Microsoft and included in Visual Studio 2010.

jQuery is a popular JavaScript framework and is often used in no-code solutions—solutions that don’t require any server-side access. You’ll find many resources on the internet for extending the SharePoint platform with jQuery. jQuery can be used to enhance your Web Parts, and you don’t have to do any cross-browser adjustments.

 

About jQuery

jQuery is a popular open source cross-browser JavaScript library that’s used as a building block to enhance the JavaScript and HTML experience.

jQuery has a pluggable architecture and can be extended using plug-ins. Microsoft has adopted the jQuery library and is shipping it with Visual Studio.

To learn more information about jQuery, visit http://jquery.com/.

 

You’ll use jQuery to extend our RSS Web Part with a timer that automatically refreshes the RSS feed at regular intervals. You’ll do this by including the jQuery library and one of the jQuery plug-ins. The jQuery version that you’ll use is jQuery 1.4.2 and the plug-in is called jQuery.timers 1.2 (originally written by Blair Mitchelmore).

First, make sure that the jQuery JavaScript file is added to the SharePoint solution. As you know, you have basically two options: add it to the _Layouts folder or into a SharePoint library. For sandboxed solutions you only have the latter option. In this example, you’re going to add all JavaScript files to the _Layouts folder. I prefer this approach when building farm solutions because it takes some load off the content databases and when I don’t have to edit the JavaScript file (which could be a good reason to put the file in a SharePoint library).

In the RSS Web Part project, you add the SharePoint Layouts mapped folder; rename the automatically added folder to DynRSSWebPart. To this folder, add a new JavaScript file called DynRSSWebPart.js that contains custom JavaScript code. Also add the jQuery file (jQuery-1.4.2.min.js) and the timer plug-in file (jquery.timers-1.2.js) to the folder.

The auto-refresh of the feed should be configurable. Add a new property to the Web Part like this:

[WebBrowsable]
[WebDisplayName("Auto refresh")]
[Personalizable(PersonalizationScope.Shared)]
public bool AutoRefresh {
    get;
    set;
}

You’ll use the AutoRefresh property in the OnPreRender method to determine if the refresh JavaScript timer should be added. Before including that check, you need to make sure that the JavaScript files are loaded by your Web Part using the ScriptLink control like this:

ScriptLink.Register(this.Page, "DynRSSWebPart/jquery-1.4.2.min.js", false);
ScriptLink.Register(this.Page, "DynRSSWebPart/DynRSSWebPart.js", false);

Add these statements to the CreateChildControls method. They ensure that the scripts are loaded only once and in the specified order. The timer plug-in JavaScript isn’t added here—you’ll do that only when the auto-refresh is enabled. You’ll use these two scripts in later enhancements of the Web Part.

In the custom JavaScript file, you need a function (see listing 10.3) to invoke the timer that will refresh the feed at regular intervals. You’ll create the JavaScript functions using JavaScript object literal notation—that is, you’ll create a namespace that holds all the functions and variables. This best practice avoids function naming collisions and saves you a great deal of troubleshooting. In this case, you’ll add an object literal to the window object only if it isn’t already defined.

Listing 10.3. JavaScript with jQuery timer plug-in that updates the Web Part partially
if (!window.feeds) window.feeds = {

    feedTimer : function (id) {
        $(document).everyTime(5000, function () {
           __doPostBack($('#' + id + ' div:first')[0].id, '');
        }, 0);
    }
};

The feedTimer function takes an ID parameter that’s the client ID of the Web Part. This function will create a timer using the jQuery Timers plug-in function everyTime, calling the inline function every 5,000 milliseconds. The function that’s called in the inline function and making the partial postback is the ASP.NET __ doPostBack JavaScript function. This function needs the client id of the UpdatePanel that will be partially updated. The client id of the UpdatePanel is retrieved using a jQuery selector. The $ function accepts a string that’s the selector. The selector looks up the HTML element with the id of the Web Part and then takes the first child div element, which corresponds to the update panel. The id of the div element is passed as an argument to the __ doPostBack function.

You could’ve passed the id of the UpdatePanel directly, and you could’ve used the ASP.NET AJAX Extensions timer control, which might have been more appropriate in this case. But I chose to use a jQuery plug-in to demonstrate the power of jQuery, jQuery plug-ins, and jQuery selectors—and you’ll use more later. Using this approach, you don’t have to write as much JavaScript code thanks to the efficiency of jQuery.

To connect the Web Part to the JavaScript and to invoke the function that creates the timer, you need to update the Web Part. In the OnPreRender method, after the code that writes the current time, add the following lines:

if (this.AutoRefresh){
    ScriptLink.Register(this.Page,
        "DynRSSWebPart/jquery.timers-1.2.js", false);
    this.Page.ClientScript.RegisterClientScriptBlock(
        typeof(DynRSSWebPart2),
        "AutoRefresh",
        string.Format("feeds.feedTimer('{0}');", this.ClientID),
        true);
}

If the AutoRefresh property is set to true, the jQuery timer plug-in script and a client script block are registered. The client script block calls the JavaScript function that’s defined in the custom JavaScript file and calls the feedTimer function with the client id of the Web Part.

When this updated RSS feed Web Part is deployed, you can select to edit the Web Part, check the AutoRefresh property, and then apply the changes. You’ll see that every 5 seconds it updates. Unless any new feed items appear in the feed, you’ll at least notice that the last updated time will change.

Using automatically updatable Web Parts like this can impact your SharePoint installation and impress your users. Imagine having Web Parts on your front page that automatically update at regular intervals or when things change.

10.2. Using the SharePoint dynamic UI features

SharePoint 2010 has received a major facelift compared to its predecessors. The user interface is built with ASP.NET AJAX Extensions, as you saw in the previous section; it provides many dynamic features. Chapter 1 reviewed some of these features. Now, in this section I’ll show you how to hook into a user interface API and use its features, such as adding notification messages to inform your users about your asynchronous operations or status bars that show errors and warnings.

If the Web Part needs to collect information from the user or show more details, the traditional way in SharePoint was to redirect to a custom application page. This made the user lose his or her current state and required that the pages be completely re-rendered. Using the new dialog framework, you can avoid this; instead, the previous application page is shown in a modal dialog window on top of the current page.

10.2.1. Notification messages and the status bar

In SharePoint 2010 you can add notifications to tell the user what’s going on and to confirm operations that are asynchronous. Another great feature is the status bar, which shows status messages, warnings, and errors. Let’s take a closer look at these new features.

Adding Notification Messages to the RSS Web Part

The last change you made to the RSS Web Part was to introduce asynchronous refreshing of the feed to avoid reloading the entire page. Unless the feed was changed, you could see that the Web Part was updated only by looking at the last updated time stamp. To improve this behavior and make it more apparent that the Web Part is actually refreshing the feed, you can use the SharePoint notification message, as shown in figure 10.2.

Figure 10.2. Notification messages can be used to inform the user about asynchronous events. This figure shows notification messages from the RSS Web Part.

You create a SharePoint notification message by invoking a JavaScript function defined in the SP.js JavaScript file, but you also need the CORE.js JavaScript file. These two files are normally included in the SharePoint master pages. The SP.UI. Notify.addNotification function allows you to add a new notification and SP.UI. Notify.removeNotification removes a notification. The notification message consists of an HTML string, and a Boolean value determines if the message should automatically disappear. Messages added are queued up and shown one after the other.

To add a notification to the RSS Feed Web Part that announces when the timer is automatically refreshing the feed, you need to add it to the JavaScript function. To do so, add a new line of JavaScript to the feed.feedTimer function so that it looks like this:

feedTimer : function (id) {
    $(document).everyTime(5000, function () {
        SP.UI.Notify.addNotification('Refreshing feed...');
        __doPostBack($('#' + id + ' div:first')[0].id, '');
    }, 0);
}

Every time the timer function is called and before the partial postback occurs, a notification message appears that informs the user that the feed is refreshing. To enhance it even further, you can add HTML with the SharePoint animated loading image like this:

SP.UI.Notify.addNotification( 
'<img src="/_layouts/images/loadingcirclests16.gif"/> Refreshing feed...');

The SP.UI.Notify.addNotification takes two parameters: the first one is the HTML you want to show in the message and the second (optional) parameter is a Boolean value indicating if the message should automatically be removed. The function returns a unique id for the notification message, which can be used to remove it (using the SP.UI.Notify.removeNotification function).

Adding a Status Bar to the RSS Web Part

The status bar in SharePoint offers similar functionality as the notification message. The big difference is that notification messages are normally messages shown for a short period whereas the status bar messages are for more long-lived conditions.

Working with the status bar is also similar to working with notification messages. The status bar is defined in the SP.js JavaScript file and you access it using the SP.UI.Status JavaScript namespace. Status messages have a title and message as well as a priority color. The big difference compared to notification messages is that the status bar doesn’t disappear after a few seconds and the status messages aren’t queued. The status bar appears by default under the Ribbon menu and messages can be appended to the status bar or removed.

To demonstrate how to work with the status bar, let’s introduce it into our RSS Feed Web Part. You’d like the status bar to appear and show if any feed fails to load. If there are several RSS Feed Web Parts on the same page, they’ll use the same status bar, as shown in figure 10.3.

Figure 10.3. Use the status bar to give the users information, warnings, and error messages. In this figure, the status bar which appears in red on your screen (“Feed not found” in figure above) shows that errors have occurred in the RSS Web Part.

You’re going to add a few new features to the JavaScript namespace that you added in listing 10.3. First you’ll add two properties that will store the id of the status bar and an array of strings consisting of URLs of the feeds not found. Then you’ll add the function that the Web Part will call whenever it finds a feed with an error. The code in listing 10.4 is added inside the window.feeds scope in listing 10.3.

Listing 10.4. Adding a status bar to the Web Part
statusId: null,
feedsNotFound : [],

feedNotFound: function (uri) {
    var html = 'Unable to locate the feed: <a href="' + uri +
        '">' + uri + '</a>.';
    var title = 'Feed not found';
    if(this.statusId == null) {
        this.statusId = SP.UI.Status.addStatus(title, html, true);
        SP.UI.Status.setStatusPriColor(this.statusId, 'red');
        this.feedsNotFound[this.feedsNotFound.length] = uri;
    } else {
        var found = false;
        for(var i = 0; i < this.feedsNotFound.length; i++) {
            if(this.feedsNotFound[i] == uri) {
                found = true;
            }
        }
        if(!found) {
            this.feedsNotFound[this.feedsNotFound.length] = uri;
            SP.UI.Status.appendStatus(this.statusId, title, html);
        }
    }
}

The first property, statusId, represents the id of the current status bar that’s used. The second, the feedsNotFound array, is used to store faulty feeds that have been added so a feed isn’t added to the status bar more than once.

The feedNotFound function takes an argument with the URL of the feed that has a problem. If the statusId property has a null value, it’ll create a new status bar and set its priority color to red and finally add the feed to the array. If a status bar already exists, the function checks if the feed has been added already to the array; if not, it’ll append a message to the current status bar and add the URL to the array.

The priority color of the status bar can have one of the following values: Red, Green, Yellow, or Blue. You should use the appropriate color like this:

  • RedIndicates errors and exceptions
  • YellowUsed for warnings
  • BlueUsed for help, notification, and information
  • GreenIndicates a good status

The SP.UI.Status namespace also contains methods for updating and removing status bars using the status id.

Carefully plan when to use the status bar or notification messages. Using these features too much will clutter your interface. A combination of standard error messages in the Web Part and these dynamic features is probably the best solution.

10.2.2. The dialog framework

Dialog windows that appear when you’re adding or editing list items are one of the most notable new features in SharePoint 2010. Using dialog windows is efficient for several reasons, such as enhanced user experience and a faster user interface.

Dialogs are created using the SharePoint JavaScript framework. The dialog framework is defined in SP.UI.Dialog.js and in the SP.UI.ModalDialog namespace. A modal dialog is created by calling the SP.UI.showModalDialog, which takes an SP.UI.DialogOptions object as an argument. The DialogOptions object defines the position, size, style, and behavior of the modal dialog.

Dialogs can be used for various tasks, such as showing information or requesting input from end users. The RSS Web Part is focused on retrieving an RSS feed and presenting it to users. To try the dialog framework and to improve the Web Part, let’s extend the Web Part options menu with a new verb that opens a dialog for changing the RSS feed URL for the Web Part. To accomplish this, you need these components:

  • A Web Part verb that invokes a JavaScript
  • A JavaScript that opens the dialog
  • A page that represents the dialog
  • A hidden field in the Web Part that contains the URL
  • Functionality to update the Web Part with the value from the hidden field

The page that will represent the dialog is built as an application page, which means that it’s stored in the _Layouts folder. Add the page by right-clicking and selecting Add > New Item on the DynRSSWebPart folder that you created in the Layouts mapped folder. Then choose the Application Page item type and name it DynRSSDialog.aspx. The page will contain a text box for the feed URL and a button that saves and closes the dialog, as shown in figure 10.4.

Figure 10.4. Modal dialogs can be created in SharePoint 2010 using the dialog framework. By using modal dialogs, you can provide a better end-user experience and a faster solution.

This code for the controls is added to the placeholder PlaceHolderMain:

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain"
    runat="server">
<h1>Change the feed Url:</h1>
<asp:TextBox ID="feedUrl" runat="server" CssClass="ms-input"  Width="255"/>
<br />
<input id='ok' type='button' value='Ok' class="ms-ButtonHeightWidth" />
</asp:Content>

Both the text box and the button have received styling using standard SharePoint CSS classes. The text box contains the URL of the current feed of the Web Part; this value is set by passing the URL as a query string parameter to the application page:

protected void Page_Load(object sender, EventArgs e) {
    feedUrl.Text = Request.QueryString["url"];
}

The text box is filled with the value in the Page_OnLoad method in the code-behind of the page. The Web Part needs a hidden field that contains the currently configured URL for the RSS. It must be exposed as a hidden field so that you can access it through JavaScript. The hidden field control is defined in the class as a private member:

private HtmlInputHidden hiddenInput;

The reason that it’s added as a private member is that it shouldn’t be overridden if the Web Part is subclassed, compared to defining it as protected. The hidden field is added in the CreateChildControls method:

hiddenInput = new HtmlInputHidden() {
    ID = "HiddenFeedControl",
    Value = this.RssFeedUrl
};
this.Controls.Add(hiddenInput);

Now you can get the value of the RSS feed using JavaScript, but you need a way to save it back if the value of the hidden field is changed. You can accomplish this by overriding the OnLoad event on the Web Part. Listing 10.5 shows how to implement the update of the RSS feed.

Listing 10.5. OnLoad method that saves the RssFeedUrl property

The OnLoad method starts by checking that the hidden field isn’t null and that the current call is a postback or a callback so that it isn’t saved on regular requests. Then OnLoad checks whether the value of the RSS feed has changed. If it has changed, then the method sets the personalization state to dirty to indicate to the Web Part Manager that it needs to save the state of the Web Part. Finally, the new value is set to the RSS feed URL and the Web Part Manager is used to save the Web Part .

Now you need to create a dialog to accept the new RSS feed URL as input and then set the value of the hidden field. You must instantiate the dialog and show it using a JavaScript function. You add this function to the JavaScript object that you created earlier for the RSS Web Part. Listing 10.6 shows the function you should add to the window.feed object.

Listing 10.6. JavaScript function that creates and shows a modal dialog window

The editFeed function takes a parameter that’s the client id of the Web Part. It creates an object called options, which contains the properties and behavior of the dialog. Properties such as title, width, and height are configured. The URL property points to the application page that you created with the current feed URL as a parameter. The current URL is retrieved using a jQuery selector, which locates the first input field in the Web Part and takes the value from it. When the dialog is closed, a JavaScript should be invoked. You define this by setting the dialogReturnValueCallback. This callback function is set to a new function that you’ll define next; this function also takes the client id as input. Finally, the dialog is shown using the showModalDialog function .

To close the dialog correctly, you need to add JavaScript to the button on the application page. This JavaScript will use a jQuery selector, so you add a ScriptLink control referring to the jQuery script:

<SharePoint:ScriptLink ID="jQuery" runat="server"
    Name="jquery-1.4.2.min.js" Localizable="false" />
<input id='ok' type='button' value='Ok' class="ms-ButtonHeightWidth"
    onclick='javascript:SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK,$("#<%=feedUrl.ClientID%>").val())'/>

The onclick attribute of the input element calls the commonModalDialogClose method with two arguments. The first one has a value of SP.UI.DialogResult.OK, which means that this is considered an OK click of the dialog, and the second one contains the value of the text box.

When the dialog closes, the callback function you defined when instantiating the dialog is invoked. The code that follows shows the closeCallback function and how it adds a notification message before updating the value of the hidden field:

closeCallback: function (result, target, id) {
    if (result == SP.UI.DialogResult.OK) {
        SP.UI.Notify.addNotification(
           '<img src="/_layouts/images/loadingcirclests16.gif"/>
           Saving Web Part...');
        $('#' + id +' input:first').val(target);
        __doPostBack($('#' + id + ' div:first')[0].id, '');
    }
}

The dialog callback checks if the result of the dialog was an OK value. If it was, then the callback shows a notification that the Web Part is being saved. This is a good spot for notification messages—telling the user that a value is saved in the background. The value of the new feed URL passed through the target argument to the method is put into the hidden field, which is found using a jQuery selector. Finally, it makes a partial post to the update panel that saves and refreshes the Web Part.

Before deploying and testing the Web Part, add a default value to the ItemCount property in the .webpart file:

<property name="ItemCount">5</property>

10.3. Enabling a Web Part to use the Ribbon

The ability to add and change functionality to the Ribbon is one of the great UI features of SharePoint 2010. Features, pages, controls, or Web Parts can add extensions to the Ribbon using custom actions. The extensions can be farm, site, all pages, or for a specific page or Web Part.

In this section you’ll explore how to enable a Web Part to use the Ribbon in two ways. First, you’ll make a Ribbon extension that appears whenever the Web Part is added to the page. This can be useful for functions that aren’t tied to the specific Web Part instance on the page.

In the second sample, you’ll take a look at something really interesting: making the Web Part contextual. This means that only when the Web Part is selected on a page will the Ribbon customizations appear. For instance, the out-of-the-box Media Web Part in SharePoint Server provides this capability. It adds a new Ribbon tab in which you can change the properties of that specific Web Part instance. You can use the Ribbon to edit Web Part properties instead of using custom Editor Parts. I’ll show you how to do the same to your Web Parts.

Before continuing, I want to warn you about building Ribbon extensions and especially contextual ones. Creating a Ribbon extension requires a lot of XML coding. If you’ve worked with previous versions of SharePoint, you’re familiar with this declarative approach. Visual Studio 2010 doesn’t offer good support for building Ribbon extensions. In addition to writing XML code, you must be able to write quite a lot of JavaScript code. The JavaScript and XML code are sensitive to which ids you assign to items, so you need to build your Ribbon extensions carefully. Hopefully this chapter will make all this easier for you.

 

Tip

Customizing the Ribbon involves server-side code, JavaScript code, and manual XML editing. There are no good tools or templates in Visual Studio 2010 to make Ribbon customizations, but you can find samples and add-ons, such as the SharePoint Ribbon Generator, in the Visual Studio Online Extension gallery.

 

10.3.1. Adding controls to the Ribbon

The functionality that you’ll add to the Ribbon in this section, is a new tab. This tab will appear in the Ribbon when you add the RSS Feed Web Part to the current page. The Ribbon tab will have a button that will refresh the feeds in all available RSS Feed Web Parts on the page. Figure 10.5 shows the customization.

Figure 10.5. You can extend the Ribbon with new tabs, groups, and controls that interact with SharePoint and Web Parts.

The first thing to do when building a Ribbon customization is to add a new SharePoint Project Item (SPI) to your project of the type Empty Element. This involves adding a new SPI to your project containing an empty Elements.xml file that will later contain the Ribbon customization. Ribbons are customized using the CustomAction element, which contains a CommandUIExtension element. Because the XML for adding a simple button is quite extensive, let’s divide it into four sections:

  • Defining the XML outline
  • Defining the tab and button
  • Defining the template
  • Defining the Ribbon actions

The outline is the basic framework for building a Ribbon extension as shown in listing 10.7. There are three spots where you’ll add the rest of the XML later. But before you delve into the details, I’ll give you a few tips for customizing the Ribbon. First, you need to be careful when defining the ids of the various nodes in the Ribbon XML. SharePoint is very sensitive to this. Make sure that you don’t reuse the same ids, and use only allowed alphanumeric characters separated by dots. Several of the ids will be converted into JavaScript namespaces and objects. Second, if you’re deploying the Ribbon and testing and making changes to it, you must clear the browser cache, because a lot of the customizations are cached in the browser.

Listing 10.7. The basic outline of a Ribbon extension

The CustomAction element is used to define any custom interface actions. The Location attribute specifies that this custom action is a Ribbon extension with the CommandUI.Ribbon value. Following the CustomAction element is the CommandUIExtension element, which contains the CommandUIDefinitions that holds the Ribbon controls and the templates . The CommandUIHandlers elements contain the definitions for the commands invoked by the Ribbon. In this sample, you use two CommandUIDefinition elements. The first one contains the definition for the tab that will be added. By looking at the Location element, you can see that this definition is going to be added as a child node to the Ribbon.Tabs object. The second element contains the template that the tab will use. A template is used to determine the location of the controls within the tab for different scalings of the Ribbon. Scalings are used when the browser window is resized to allow the Ribbon to adapt to the space available to rendering controls. For instance when your browser window gets smaller you can make your Ribbon controls smaller or even group them. In this sample, you’ll use only one template, which means that this Ribbon extension won’t scale. Listing 10.8 shows the XML that defines the tab that should be added in the first CommandUIDefinition element in listing 10.7.

Listing 10.8. Adding a custom tab to the Ribbon

The Tab element defines the tab that you’ll add to the Ribbon; it has a title and description. All elements in the XML must have an Id attribute. Omitting this attribute will result in the Ribbon failing to render properly. The Sequence attribute defines the order of the control. The first element under the Tab element is the Scaling element, which defines how this tab should handle scaling. The Ribbon automatically scales when the browser window is resized. For this tab, you define two sizes. The Scale and MaxSize elements have a Size attribute that determine which layout from the Ribbon templates to use. In this case they both share the same template, so no scaling will occur. Each scaling element must have a GroupId element that references the group to scale. The Groups element defines the different groups within this tab. Here, only one Group element is used. The Template attribute specifies the id of the Ribbon template you want to use (you’ll define that shortly). Each group has a set of controls defined under the Controls element. The Button control you’ll use to refresh all feeds uses the LabelText attribute for the text and a set of image attributes to set the image to be used. The TemplateAlias is used to match the position in the Ribbon template. There are two images: one 16×16 pixels and the other 32×32 pixels. Which image the button will use depends on the scaling. The images are rendered using CSS sprites, so each image has a top and a left value. You can see the image used in this sample in figure 10.6. The Command attribute is the name of the command to be executed when the user clicks the button.

Figure 10.6. You should use CSS sprites, which use images combined into one image file, when adding images to controls in the Ribbon to improve performance and reduce request load on the server.

Our next task is to create the template that’s referenced by the scaling, group, and controls. The template is placed in the second CommandUIDefinition element in listing 10.7. Listing 10.9 shows how to build the template. You can use several templates for scaling the Ribbon, but because this tab contains only one button, that won’t be necessary.

Listing 10.9. Defining a Ribbon group template

Each template is contained in a GroupTemplate element that has an id that’s used by the Template attribute on the Group element in listing 10.8. There can be multiple Layout elements where each has a unique LayoutTitle attribute that’s used by the scaling elements (Scale and MaxSize). The Layout contains sections that have Rows or Strips. A Row or a Strip contains ControlRef elements, which are placeholders for the controls. Each ControlRef element has a DisplayMode that determines the layout of the control. You have to pay attention to which DisplayMode is used with which control. Not all controls support all display modes. The TemplateAlias attribute specifies the name of the control reference and is used by the controls in the Ribbon.

 

Note

You should always create your own group templates and not reference templates from other projects or the out-of the box Ribbon. This will ensure that the template is loaded when referenced by your controls.

 

The last part of the Ribbon XML defines the action that’s executed when a user clicks the button. For simple actions, this can be defined in XML, but for more advanced operations a custom Page Component JavaScript is needed, as you’ll see in the next sample. The command is defined as follows and the CommandUIHandler elements are placed in the CommandUIHandlers element in listing 10.7:

<CommandUIHandler
    Command="WebPartsInAction.RefreshCommand"
    CommandAction="javascript:feeds.refreshAll()"/>

Each CommandUIHandler has a Command attribute that contains the name referenced by the Command attribute of the control. The CommandAction attribute defines the command to be executed. In this case it invokes a JavaScript method. The JavaScript method is added to the JavaScript namespace that you created earlier:

refreshAll: function () {
    SP.UI.Notify.addNotification('Refreshing feeds...');
    $(".feedWebPart div:first").each(function () {
        __doPostBack($(this)[0].id, '');
    });
}

The method will display a notification message and then use jQuery to find all elements that have the CSS class feedWebPart and then the first div in that HTML element. Using the id of each of those div elements, it’ll make a partial update. To add the CSS class to the RSS Feed Web Part, add the following to the CreateChildControls method of the Web Part:

this.CssClass = "feedWebPart";

There’s one more thing to do before you can see the Ribbon: configure the Web Part to show the Ribbon when it’s added to a page. In the CreateChildControls method, add the following:

SPRibbon current = SPRibbon.GetCurrent(this.Page);
if (current != null) {
    current.CommandUIVisible = true;
    current.MakeTabAvailable("WebPartsInAction.RssTab");
}

This code retrieves the current instance of the Ribbon. If the Ribbon is available, the code will make sure that the Ribbon is visible and then make our RSS Feed tab available. The MakeTabAvailable method requires that the Microsoft.Web.CommandUI. dll be added as a reference to the project. This assembly is found in {SharePoint Root}\ISAPI.

Now you’re all set to build and deploy. Add two or more RSS Web Parts to a page and configure them. Click the Refresh Feeds button in the custom Ribbon tab and watch the times in the Web Parts change.

You can use the same method to add Ribbon customizations to a page using delegate controls, traditional server or user controls, or even add Ribbon controls directly to a custom page. Ribbon customizations aren’t specific to Web Parts. In the next sample, you’ll look at a Ribbon customization that’s for Web Parts only.

 

Tip

Full reference of the Server Ribbon Schema can be found in the SharePoint 2010 SDK at the Microsoft MSDN site: http://msdn.microsoft.com/library/ff458369.aspx. The default Ribbon in SharePoint 2010 is defined in the CMDUI.XML file, located in {SharePoint Root}\Template\Global\Xml. I suggest you look at that one to get inspiration and ideas for your own Ribbon customizations.

 

10.3.2. Making a Web Part context aware

The previous sample added a custom Ribbon tab to a page when a Web Part appeared on the page. This customization was quite generic and not only applicable to Web Parts. But what if you’d like to add to the Ribbon a custom tab that’s tied to a Web Part? That way, when the Web Part is selected the Ribbon extensions become available. This is called a context-aware Web Part and is used, for instance, by the Media Web Part in SharePoint 2010 Server. When that Web Part is selected, the media options appear in the Ribbon.

I’ll show you how to make the RSS Web Part context aware. When the Web Part is selected, a new contextual Ribbon tab will appear and allow you to edit the feed URL from the Ribbon instead of using the Editor Part. The Ribbon XML is built in much the same way as the previous approach, with just a few changes. The JavaScript is more complex and you need to make more edits to the Web Part code. The result will look like figure 10.7.

Figure 10.7. Ribbon tabs can be made contextual so that they’re visible only when specific Web Parts are selected.

Build the Ribbon XML

The first thing to do is to add a new Empty Element SPI to the project that will contain the XML for the contextual tab. The XML is much like the previous one, but you have to change the Location attribute of the CommandUIDefinition so that the new tab is added to the contextual groups of the Ribbon like this:

<CommandUIDefinition Location="Ribbon.ContextualTabs._children">
    <!-- Tab -->
</CommandUIDefinition>

Instead of adding a Tab element, you add a new contextual group using the ContextualGroup element and in that group you add the tab. Listing 10.10 shows how the contextual group, tab, and controls are built.

Listing 10.10. Creating a contextual group containing a Ribbon tab

The ContextualGroup element encapsulates the tabs in this ribbon customization; it has a title and a color . The Tab element follows the contextual group, looking the same as in the previous sample. The Scaling element also looks the same, except that the custom Scale element in this sample uses a second template . After the Scale element comes the Groups element, and then the Group element, which contains the controls. For this contextual tab, a TextBox element contains the URL of the RSS feed. The text box uses a QueryCommand attribute to define the function that will be called when the tab is activated or changed. This command will later be implemented using a custom page component instead of a CommandUIHandler. The last element is the Button element , which will save the value from the text box to the selected Web Part. The Command attribute for the button will be handled by a JavaScript function in the page component.

Several other elements in listing 10.10 have the Command attribute. This attribute is needed to enable those parts of the Ribbon even though there’s no code or logic behind those commands. For instance, the text box would never call the QueryCommand function if there were no Command functions defined.

The Ribbon template for this contextual tab will use two different templates, instead of just one as in the previous Ribbon sample. Listing 10.11 shows the GroupTemplate element of the contextual Web Part group.

Listing 10.11. Ribbon template with two layouts

The GroupTemplate contains two Layout elements. The first is used when the Ribbon uses the max size scaling. The second one is used when the browser window is resized and the max size template doesn’t fit in the browser. The only difference in this case is that the button, which uses the ctrl2 TemplateAlias, will be displayed using a small image when using custom scaling instead of a large image.

Create a Page Component

When building more advanced logic for the various Ribbon commands, you can use a page component. A page component is a custom JavaScript object that’s inherited from a base Page Component object. The Page Component object exposes several methods that can be used to make the Ribbon more dynamic.

You create a page component by building a JavaScript object. For that you need to add a new JavaScript file to the project. Name the file RSSRibbon.js and add it to the Layouts mapped folder. The page component is implemented in listing 10.12. The JavaScript object model in SharePoint extensively uses the ASP.NET AJAX framework, and if you’re familiar with those JavaScripts, you’ll recognize several parts of this implementation.

Listing 10.12. The page component required for the contextual Web Part

First, a new namespace is registered ; this one is called RssWebPart. This namespace is then used to contain the page component, which is called CustomPageComponent . Objects in JavaScript are defined using the function keyword, and this function is also its constructor. This definition will store a local variable containing the id of the page component, which is unique for each Web Part. One page component object is created per Web Part. Finally, the constructor calls its base object, which will be configured later. To define methods on the JavaScript object, you use the prototype keyword. You define the init method that’s used to initialize the object but in this case does nothing. Then you define the getFocusedCommands function . This function returns an array of names of the Ribbon commands that should execute when the control has focus. The getGlobalCommands function also returns an array of commands, but these commands are executed regardless of focus. The canHandleCommand function takes a command as an argument and decides whether the command can be executed. For this example, all focused commands can be executed.

If the command can be handled, then it will be invoked using the handleCommand function. This function is where the action takes place in the page component. The function takes the command as a parameter, and then depending on which command is called, the page component executes different code. When the tab gets the focus, it will call the command defined in the QueryCommand attribute of the text box. This command retrieves the value from the hidden field, which you previously created in the Web Part, and sets that value into the properties argument object . The Ribbon uses this properties object to set the value of the text box control. When the user clicks the save button, the command of that Button element is called . This command will get the value from the text box and put it into the hidden field. All other commands defined in the getFocusedCommands aren’t handled specifically.

The getId function returns the current id of the page component instance. The isFocusable function always returns true and tells SharePoint that the contextual group can get focus.

The final task is to register this object as a class using the ASP.NET Ajax register Class function . This function takes the name of the class and the base object (CUI.Page.PageComponent) from which it will inherit logic. You’ve just overridden a few of the base object methods, but there are more, such as yieldFocus and recieve Focus, which can be used to execute code when the contextual group yields or receives focus.

 

Tip

The documentation of Page Components is, at the time of writing this book, very sparse but can be found at http://msdn.microsoft.com/library/ff408634.aspx.

 

To connect the RSS Web Part, the contextual Ribbon tab, and the page component, you need wiring code. First, create a JavaScript that instantiates a new page component using the unique Web Part Component Id for the Web Part. For this you’ll use a new JavaScript object called pageComponentFactory. This object is made to handle instances when you use UpdatePanel controls on the page. When a Web Part with a page component gets partially updated, SharePoint will re-create all the page components on the page. The Ribbon will then lose the connection to the page components and stop working. It’s here that the pageComponentFactory comes to the rescue and makes sure that the page components aren’t recreated during a partial update by storing the reference between the page component and the Web Part.

You add the pageComponentFactory object to the same JavaScript file, although you could move it to a separate JavaScript file so that you could reuse it more easily. Listing 10.13 shows the implementation of the pageComponentFactory object.

Listing 10.13. The pageComponentFactory object

The pageComponentFactory constructor takes four arguments. The first is the id of the Web Part component and the second is the class that was registered. The last two parameters are the name and location of the JavaScript file where the page component is registered. The object contains one local method called add , which instantiates the page component if there isn’t already a page component with the specific id created. Then it adds the page component to the SharePoint Ribbon Page Manager.

The JavaScripts in SharePoint contain a set of functions called Script On Demand (SOD). These functions allow you to register JavaScript files as they’re loaded and notify registered functions to execute when they’re loaded. The second method of the page component factory is the register function. The register function is the first method called; it will register the JavaScript file using the SP.SOD.registerSod function and then connect the page component class and method to it using the SP.SOD.executeFunc function. Once the JavaScript file is loaded by SharePoint, it will execute the function specified in the last parameter, in this case the add function.

 

Tip

More information about the Script On Demand functions in SharePoint 2010 can be found in the SharePoint 2010 SDK; http://msdn.microsoft.com/library/ff410742.aspx.

 

To use this page component factory, you add a function to the JavaScript file. This function will be called from the Web Part using the page component id that will be used for the Web Part:

function createRssRibbon(webPartPageComponentId) {
    return new pageComponentFactory(webPartPageComponentId,
        'RssWebPart.CustomPageComponent',
        'DynRSSWebPart/rssribbon.js',
        '/_layouts/DynRSSWebPart/rssribbon.js');
}

This function takes the id of the Web Part page component as parameter and then creates a new pageComponentFactory object specifying the class and the JavaScript. When the register method is called on the returned pageComponentFactory object, it will wait for the RSSRibbon.js file to load; the method then invokes the add method, as in listing 10.13.

You have one more thing to add to the custom JavaScript file (RSSRibbon.js): the code that informs the SOD Manager that the file is loaded. This has to be added to the end of the JavaScript file:

SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs(
    "DynRSSWebPart/rssribbon.js");
Connecting the Web Part to the Page Component

Now that you have all the necessary JavaScript code for the contextual Web Part, it’s time to modify the Web Part so it can connect to the Ribbon and page component. The first thing that you need to do is make the Web Part class implement the IWeb PartPageComponentProvider interface. This interface contains one property that returns information about the current Web Part Ribbon status. When the Web Part Manager adds the Web Parts to the page, it queries for this interface; if it’s found on a Web Part, the Manager will retrieve the contextual and page component information from the Web Part and register the associated Ribbon tabs. Modify the class definition of the Web Part so that it looks like this:

public class DynamicRSSWebPart : WebPart, IWebPartPageComponentProvider

Then right-click on the newly added interface and select Implement Interface > Implement Interface. This adds the property of the IWebPartPageComponentProvider interface to the Web Part. Change the implementation so that it looks like listing 10.14.

Listing 10.14. Implementing the IWebPartPageComponentProvider interface

The property returns a WebPartContextualInfo object. This object contains a list of WebPartRibbonContextualGroup objects, which are the contextual groups associated with the Web Part specified using the Id attribute . The object also contains the associated tabs defined by a list containing WebPartRibbonTab objects using the Id of the tab . The VisibilityContext property used by both objects must be unique. Finally, the PageComponentId property is set using the built-in function of the SPRibbon class to get the unique id for the page component.

Now the Web Part Manager is aware that this is a Web Part with a page component and it has added the contextual group and tab to the Ribbon. It doesn’t yet have the information about the page component and JavaScripts. The JavaScripts are registered in the CreateChildControls:

ScriptLink.RegisterScriptAfterUI(this.Page,
    "CUI.js", false, true);
ScriptLink.RegisterScriptAfterUI(this.Page,
    "SP.Ribbon.js", false, true);
ScriptLink.RegisterScriptAfterUI(this.Page,
    "DynRSSWebPart/RssRibbon.js", false);

Three JavaScripts registrations are added. The first to be registered is CUI.js, which contains the base definition for the page component. Next the SP.Ribbon.js file is registered. This file contains the Ribbon Page Manager that’s used by the page component factory. Finally, the custom JavaScript file for the RSS Feed Web Part is added; this file contains the page component. The two first JavaScripts are SharePoint JavaScripts, but you’ve added them here so you’re sure that they’re loaded.

All that is left is to create the Page Component in the Web Part. You create the page component by using a JavaScript that calls the createRssRibbon function in the JavaScript file. To invoke this function, use the ScriptManager to register a new startup script in the OnPreRender method:

ScriptManager.RegisterStartupScript(this.Page,
    typeof(DynamicRSSWebPart),
    "RssWebPartPageComponent" + this.ClientID,
    string.Format("SP.SOD.executeOrDelayUntilScriptLoaded(" +
        "function(){{createRssRibbon('{0}').register();}}," +
        "'DynRSSWebPart/rssribbon.js');",
        SPRibbon.GetWebPartPageComponentId(this)),
true);

This registration will add a new script for each Web Part that’s executed once the RSRibbon.js file is loaded. It will then call the createRssRibbon function using the unique Web Part page component id.

It took a lot of code, both XML, JavaScript, and server-side C#, to finish this contextual Web Part, but now it’s ready for a test drive. Build the project and deploy it to your SharePoint site; then add a few of the Web Parts to the page and configure them using the contextual tab. Each time you select a new RSS Web Part on the page, the page component will retrieve the value from the hidden field and populate the text box. And when you click the save button, it will copy the value from the text box to the Web Part hidden field. Then the page component makes a partial update that saves the new value of the feed URL and updates the Web Part.

10.4. Summary

By using all the dynamic features—such as the built-in notifications and dialogs, the Ribbon framework, and ASP.NET AJAX extensions—you can make your Web Parts more user-friendly and more Web 2.0-ish.

You must have knowledge of JavaScript to be able to build dynamic Web Parts, and I recommend that you learn how to use jQuery as well. Using jQuery in combination with the plug-ins allows you to build JavaScript code quickly and you don’t have to worry so much about browser compliancy.

In this chapter you did a combination of server-side and client-side programming using JavaScript, jQuery, XML and C#. In the next chapter you’ll continue exploring JavaScript and also create a Web Part using Silverlight.