Tuesday, 7 October 2008

Ajax Web Parts Part 3 - Dynamic Web Parts

Posts In This Series:

Introduction - ASP.NET AJAX and Web Parts
Ajax Web Parts Part 1 - Drag and Drop
Ajax Web Parts Part 2 - Web Part Connections
Ajax Web Parts Part 3 - Dynamic Web Parts
Ajax Web Parts Part 4 - Dynamic Web Part Connections


Download the source - Part 1
Download the source - Part 2
Download the source - Part 3
Download the source - Part 4




Introduction

So far, in this series on Ajax Web Parts, all the components have been created at design time. The Web Part Zones, the Web Parts themselves, and the connections between them, have all been added statically to the page markup.

In order to achieve our ultimate goal, of movable Web Parts in a user created tab framework, we now need to change to using dynamically created components:

  • Web Part Zones need to be dynamically created so that, eventually, they can be used to populate each tab page.

  • Web Parts and their connections need to be generated at run time to populate the Web Part Zones.

Therefore, we will now investigate how the previous project can be changed to add these dynamic components.



Creating Dynamic Page Components

The easiest way to create dynamic page components is by copying static components – that is, firstly create the required components in the ASP.NET markup and then, once this is working, copy the structure to create the same components dynamically.
We will use this approach to replace the Web Part components that were statically created in the last posts, with a new class that can dynamically generate the same components.



A Dynamic Web Part Class

Rather than simply adding everything to the web form’s code-behind file, we will create a class to create the dynamic components. So first of all, we need to add a new class to the project as follows:


  1. Right-click on the project’s “app_code” node and choose “Add New Item”.
  2. In the dialog that appears choose to add a new class and give this the name “DynamicWebParts.cs”.
  3. Once the class has been added to the project, change the constructor so that it takes an instance of the page and add a property to hold a reference to this value. This is required to give us something to add our components to. The page comes from the System.Web.UI namespace, so a “using” line needs to be added for this.


At this stage the class should look as follows:




In addition to a page, to which the Web Parts can be added, the other thing that is required to create dynamic Web Parts is a Web Part Manager. For now we will simply pass through the static Web Part Manager that exists on the page and store this into a property as follows:



private WebPartManager itsManager;
public WebPartManager Manager
{
set { itsManager = value; }
}


Namespace Selection

If you remember from the previous posts, to get cross-browser drag and drop support we needed to use the Web Part Manager from the Microsoft Web Preview release. Therefore we need to use the same version here in our class. Therefore, at the top of the page the following “using” statement is required:


using Microsoft.Web.Preview.UI.Controls.WebParts;


This namespace is used to give us the Web Part Manager and Web Part Zones needed for cross-browser drag and drop.
However, the Web Parts themselves still come from the standard System.Web.UI.WebControls.WebParts namespace. Therefore, to avoid a clash, we need to explicitly state that the Web Part Manager and Web Part Zones come from Preview DLL. This can be done by specifying the full namespace every time we refer to the WebPartManager and WebPartZones. However this is rather cumbersome.

A more elegant approach is to add an alias so that both WebPartManager and WebPartZone will always reference the Preview DLL's versions. To do this the following lines should be added:




using WebPartManager = Microsoft.Web.Preview.UI.Controls.WebParts.WebPartManager;
using WebPartZone = Microsoft.Web.Preview.UI.Controls.WebParts.WebPartZone;


(Another approach that can be used to specify which DLL to use, when referring to a control, is to use tag mapping in the web.config file. However, this will only work for controls declared in markup and is therefore not appropriate for dynamically created controls. See David Barkol's blog for details)



Dynamic Web Parts

Everything is now in place to allow us to dynamically add some Web Parts to the page. As a first step, let’s replace the static Provider and Consumer Web Parts that were created in the last part of the series. Both of these Web Parts were formed by taking User Controls and adding them to Web Part Zones to create Web Parts. We will use a similar approach when dynamically generating the Web Parts. The function to take a User Control and add it to a Web Part Zone is shown below:





Notice how the steps required to dynamically add a Web Part closely resemble those used to statically add one:

· once again a User Control is loaded (using the Page’s LoadControl function)
· a Web Part is then created (by calling the Web Part Manager’s CreateWebPart function) and added to a Zone (using the Web Part Manager’s AddWebPart function).

Other points to note here are:
1. We’ve created a unique ID for control by simply taking the title supplied for the Web Part and removing any spaces from it.
2. To get the Web Part Zone we need to search the Web Part Manager’s list of Zones until the supplied name is found.
3. The Web Part Manager’s AddWebPart function takes a copy of the supplied Web Part and returns a reference to the copy. Therefore it is this that needs to be returned to get access to the Web Part that actually exists on the page (rather than the Web Part that was created using CreateWebPart).


All that’s required now is to actually use this new function to programmatically generate some Web Parts. Therefore, back in the Default.aspx.cs code behind file, add the following:




This creates an instance of our new class, sets the Web Part Manager to the one that exists in the markup and then creates 2 Web Parts – a Provider, which is added to the first Web Part Zone and a Consumer, which is added to the second Web Part Zone.

Running this should give the following output:





Click here to see this in action.

Note, that at this stage, the dynamic Web Parts cannot be moved between zones. Trying to move them results in more Web Parts appearing. This is a result of the way in which the standard Web Part Manager assigns IDs to the Web Parts and we'll look at this more closely in the next post.


Conclusion

Both statically and dynamically created Web Parts now exist on the page. The statically created Web Parts have a connection between them; any text typed into the input field of the provider Web Part will appear in the label of the consumer Web Part when the button is clicked. The dynamically created Web Parts are not yet connected and, as we'll see in the next part of this series, creating this connection is not as straightforward as it should be (this seems to be a recurring theme!). In addition, drag and drop doesn't yet work for the dynamically created Web Parts - this is something that will also be resolved in the next post.

No comments: