IN THIS CHAPTER
In Chapter 25, “ASP.NET Personalization and Customization,” you learned how to use themes, skins, and user profiles to store meaningful information about users and to enable those users to make decisions about the look and feel of individual pages or an entire website.
This chapter introduces you to the concept of Web Parts, which give users control over both the layout and the content of pages, providing an extremely powerful user experience. You will learn the basics of what Web Parts are and how they work, as well as how to place Web Parts on a page, create Web Parts, and even build connected Web Parts.
Web Parts are special controls that are designed to provide the user with discrete units of functionality that can be placed on a page in virtually any location. A discrete unit of functionality essentially means that the Web Parts are designed to perform specific tasks such as displaying an inbox, providing a task list, displaying the current weather, and so on. Web Parts are not entire applications encapsulated in a control. The suite of Web Part tools allows the developer to quickly and easily create pages (called Web Part Pages) that host Web Parts. Such pages can allow users to control the layout by dragging and dropping Web Parts to move them into the location that the user chooses. Users can also control Web Part properties; they can minimize or even close Web Parts just as they would manipulate Windows on their desktop. All of this functionality is virtually free for the developer utilizing the Web Parts suite of controls and ASP.NET 2.0.
There are many reasons to use Web Parts. If you want to provide your users with functionality, but you want your users to be able to choose what data is presented to them, and how that data is presented to them, Web Parts will definitely provide you with a huge boost in productivity, time to market, and application functionality.
Web Parts make use of the personalization provider to store personalization data. When a Web Part is added to a page, it contains both shared data and personalization data. This means that a control can have a set of properties that are shared among all users. When a user chooses to customize that Web Part, his personalization data overrides the shared data, creating user-specific settings. For example, you could create a Weather Web Part that has a shared setting of ZipCode
that defaults to the ZIP code of the website’s headquarters. When users choose to customize that Web Part with their own ZIP code, they create a user-specific setting that overrides the shared default.
Figure 26.1 shows a conceptual mock-up of what a sample Web Part Page might look like. The page has been divided into zones in which Web Parts can reside. The page in Figure 26.1 has Web Parts for displaying news, weather, a to-do list, the user’s inbox, and a site navigation control. A fully functioning Web Part Page containing these Web Parts would allow the user to choose which parts were visible, where those parts sat on the page, and even things like whether the part should display a header or a border. If the Web Part had custom properties (such as the ZIP code for local weather), the user could also choose to supply that information.
Figure 26.1 A Web Part Page conceptual diagram.
Several controls and classes provide the core framework for Web Parts. Table 26.1 contains a list of the key component controls required to make the Web Parts functionality possible.
Table 26.1 Web Part Controls
Additional controls are used in conjunction with the ones listed in Table 26.1, but the ones in Table 26.1 are the controls you should be concerned with at the top level.
The key to working with Web Parts is in knowing what they can and cannot do. Every time you add a server or user control into a ZoneTemplate
within a WebPartZone,
that control is encapsulated within a GenericWebPart
control. Before you start coding your own Web Parts and working with them, you should know how this class works, because it and the WebPart
class form part of the foundation of the Web Parts framework. The GenericWebPart
class is generated at runtime to allow user controls and other non-Web Part controls to have access to Web Part functionality.
Tables 26.2 and 26.3 show some of the common properties and methods of the WebPart
class, the class from which all WebParts (including GenericWebPart
) inherit.
Table 26.2 Common WebPart
Properties
Table 26.3 Part-Specific Control Methods
Using the personalization provider is actually pretty easy. All of the code that communicates directly with the provider is contained within the Web Parts set of controls and classes. This means that the only work you need to do is to configure the personalization database and modify the Web.config
file to indicate the appropriate provider connection string.
Creating the personalization database is actually done by creating the Application Services database using the instructions in Chapter 25.
Open a Visual Studio 2005 Command Prompt window and type aspnet_regsql
on the command line. You will be presented with the ASP.NET SQL Server Configuration Wizard. This wizard will prompt you for the location of a SQL Server instance as well as the credentials needed. You can also choose whether you want to create the Application Services information in a new database or configure an existing one. When you have completed this wizard, you will have created an Application Services database that hosts the data, metadata, and stored procedures required to support the membership, roles, profile, and personalization providers.
After you have created your Application Services database and you’ve verified that it is available and ready to be accessed, you need to modify your web application’s Web.config
file to point the personalization provider at this location. A sample Web.config
configured for personalization is shown in Listing 26.1.
Listing 26.1 A Personalization-Enabled Web.config
File
This Web.config
file indicates that the System.Web.UI.WebControls.WebParts.SqlPersonalizationProvider
will be used as the personalization provider, and it will use the database indicated by the connection string named AppSvcsConnection.
Run an empty default.aspx
in an application with the Web.config
file from Listing 26.1 and see if it works. If no runtime errors occur while trying to load the default page, you can assume that a personalization connection was made to the database and you can continue on to the next section to create your first Web Part Page. If you do have errors, there is usually enough information in the error message to indicate what went wrong. Make sure to change the database
and server
options in your connection string to match the information you provided when you created the Application Services database using the aspnet_regsql
wizard.
The steps in this section walk you through the process of creating your first Web Part Page. At first it can seem very overwhelming as there are a lot of new controls to use and a lot of new terminology. After you have completed the Web Part Page, you are strongly encouraged to play with it, modify it, and experiment with it before continuing on to the next section so that you can familiarize yourself with the behavior and functionality of Web Parts within ASP.NET 2.0. Rather than have you examine the completed solution, this section is designed to walk you through all of the individual steps required in creating a Web Part Page so that you can gain a thorough understanding of the process and can reuse that process in your own applications. Use the following walk-through to create your first web part page:
FirstWebPartPage.
When you have the application created, modify the Web.config
so that it points to the personalization provider created in the preceding section. Your new Web.config
should look a lot like the one shown in Listing 26.1.default.aspx
and create a three-column table in between the default <div>
tags. Make sure that your View menu (when looking at the designer view) has both Non-Visual Controls and Details checked so that you can see everything that’s going on in both source view and design view.WebPartManager
component from the Toolbox onto your web page (this works in either design or HTML view) directly above the three-column table created in step 2. Rename the component to wpManager.
The WebPartManager
provides the plumbing necessary to convert a standard page of static controls into a dynamic Web Part Page.WebPartZone
from the Toolbox into the leftmost table cell in the first row of the table you created earlier. Call this control zoneSideBar.
Set the HeaderText
property to "Side Bar".
WebPartZone
control from the Toolbox into the middle column of the table. Call that control zoneMain.
Set the HeaderText
property to "Main Zone".
WebPartManager
followed by a three-column table. The left column should contain the zoneSideBar
control and the middle column should contain the zoneMain
control. From the design view, drag a TreeView
control and drop it in the box framed by the side bar zone. Feel free to add random nodes and format it as you see fit. The important thing to note is that when you switch to source view, you will see that the TreeView
is now contained within a ZoneTemplate
element inside the zoneSideBar
control. At runtime, the TreeView
control will automatically become the child control of a GenericWebPart
, giving it access to all of the functionality provided by the Web Parts engine.TreeView
control is inside another frame labeled “Untitled” with the Web Part menu down-arrow icon. This is because the TreeView
is actually inside an unlabeled GenericWebPart.
To fix this, you can add title="Tree"
to the TreeView
’s declaration. You’ll get a warning message about it in the source view, but you can ignore it because when you switch back to the design view, "Untitled"
will have been replaced with "Tree"
.zoneMain
zone control. Don’t worry about separating them with <br/>
tags—the fact that they are contained within a WebPartZone
will automatically make them appear within their own frames. Call them lblOne
, lblTwo
, and lblThree
respectively. You can add whatever text you like to them. Set the Title
property on them using the source view. If you feel like it, you can right-click zoneSideBar
and zoneMain
, choose Auto Format, and select something more colorful than the default zone colors. Figure 26.2 shows a screen-shot of the author’s designer at this stage of the walkthrough.
Figure 26.2 Visual Studio 2005 Designer, building a Web Part Page.
PageStateSwitcher.ascx
.PageStateSwitcher.ascx
code to the following:
PageStateSwitcher.ascx.cs
file and enter the following source code:
default.aspx
in whatever view you want and drag PageStateSwitcher.ascx
from the Solution Explorer onto the design surface below the three-column table, just before the last </div>
tag.
default.aspx
and play around with the page for a while. Notice that when you switch the page into Design mode, borders appear around each zone as well as the zone’s name. To watch the real magic happen, left-click and hold on a Web Part’s title bar (while in Design mode) and drag it into some other location. You can move Web Parts between zones as well as change their display order. To prove that personalization is remembering your changes, make some visible changes to the page, close the page, and then reopen it. It will reappear in the same state in which you left it.
EditorZone
. To create an EditorZone
, drag one from the Toolbox into the third column of the table that hasn’t been used yet. Rename this control to zoneEditor
.AppearanceEditorPart
and a LayoutEditorPart
into the EditorZone
control. You’ll see that both of those parts will also be wrapped in a ZoneTemplate
control. Note that if you drag these controls while in source view, you will have to create the ZoneTemplate
element manually.
EditorZone
will appear, as shown in Figure 26.3.
Figure 26.3 A Web Part Page with editing enabled.
aspx
within a WebPartZone
. With a little bit of work, you can also allow users to interactively select which Web Parts they want on their page by picking them from a catalog. To add catalog support to your page, start by dragging a CatalogZone
control onto your page directly below the EditorZone
you just created.
DeclarativeCatalogPart
, which allows you to declare the list of parts contained in the catalog directly within the page. Drag the DeclarativeCatalogPart
from the Toolbox in design view into the CatalogZone
just created. VS will create the ZoneTemplate
for you.
DeclarativeCatalogPart
, or you can go into source view and create a WebPartsTemplate
child element and declare the controls within that element. For this walkthrough, place a Calendar
, a TextBox
, and a Label
with some random text into the WebPartsTemplate
. Also remember that you can add any control here: a user control, a standard ASP.NET server control, or a control you have created that inherits directly from WebPart
.
WebPartsTemplate
, add a Title
property to each of them so that the catalog has some way of displaying a description of the Web Part to the user. The code for your DeclarativeCatalogPart
will look similar to this:
Catalog.
Select this display mode and the CatalogZone
will appear. It will then display a list of checkboxes next to the titles of the controls you added in step 20. You can see how the catalog will allow you to add Web Parts by selecting them and choosing the zone in which you want them to appear. Figure 26.4 shows a sample page after the user has added the Calendar
control to the Side Bar zone.
Figure 26.4 Using the catalog zone to add Web Parts at runtime.
There are several different ways to create a Web Part. The first and easiest way is to simply take an existing ASP.NET control and place it inside a ZoneTemplate
. At runtime, that control will automatically be wrapped inside a GenericWebPart
control. This automatic promotion of regular controls to Web Parts makes using existing controls in Web Part Pages extremely easy.
A second way to create Web Parts is to create a control that derives from the WebPart
class. Although this approach provides the developer with the most direct control over the behavior of the Web Part, it also doesn’t allow you to use a designer and requires you to have some knowledge of custom control creation, which is covered in Chapter 30, “Developing ASP.NET Controls.”
The third way is to create a user control that performs the function you want. After the user control has been created, you can place it within a WebPartZone
and it will not only function like a standard Web Part, but it will also have access to all of the Web Part functionality available in the ASP.NET Web Part engine.
Creating user controls isn’t the focus of this chapter, but there are some additional things that you can do within a user control or within any other class to make the control compatible with the personalization provider. If you create a Web Part and you want to be able to expose a property of that Web Part so that the data can be stored in the personalization store, you can use the PersonalizableAttribute
class. You use this attribute to decorate a property just as you would with any other attribute, as shown in the following code:
[Personalizable(PersonalizationScope.User)]
public string ZipCode
{
get { return zip; }
set { zip = value; }
}
You can also use the WebDescriptionAttribute
and WebDisplayNameAttribute
attribute classes to further decorate a property so that it will show up properly in an EditorZone
. WebDescriptionAttribute
indicates the tooltip that will be used for a Web Part property, whereas WebDisplayName
indicates the friendly name that will be displayed for a Web Part property:
[Personalizable(PersonalizationScope.User)]
[WebDisplayName("Zip Code")]
[WebDescription("Zip Code Used for Local Weather Forecast")]
public string ZipCode { ... }
The next section on building connected Web Parts will give you a thorough walkthrough of creating user control-based Web Parts.
One of the most powerful things that can be done by Web Parts is to share data among parts within the same zone or even between different zones. A really common scenario among portal-style pages is to provide information based on the user’s ZIP code. For example, when you log on to a portal for the first time, you typically add content to your page like local movie listings, weather reports, and local news. All of these could easily be written as ASP.NET 2.0 Web Parts. The issue is how to feed all of the Web Parts the same information: your ZIP code.
Data is shared among Web Parts in ASP.NET 2.0 using a publish/consume model. A Web Part can publish a piece of information that can then be consumed by any other Web Part that knows how to consume that information. This means that you could create a Web Part that prompts the user for her ZIP code and then publishes that information to all interested Web Parts. Without prior knowledge of other existing Web Parts, a developer could create a Web Part that consumes ZIP codes and an end user or administrator could utilize a ConnectionsZone
to hook up publishers and consumers on the same page.
This is all made possible through a contract by which publishers and consumers both must abide. As you know, in programming terms, a contract is an interface. When a Web Part publishes data, it publishes that data in the form of an instance of an object that implements a specific interface. All a consumer has to do is implement a method that receives an instance of that same interface. The Web Part plumbing in the underlying connection takes care of calling the publishing method on the publisher and the consuming method on the consumer.
To illustrate connected Web Parts, this section walks you through adding a shared interface and two new user controls to the solution developed in the previous section, FirstWebPartPage
.
Before creating any controls, add an App_Code
folder to your web application and place the IZipCode
interface in it. The code for the IZipCode
interface is quite simple:
This simple interface indicates to any consumers that the data being published is a string representing a ZIP code.
The first control is a simple control that prompts the user for his ZIP code. The beautiful thing about it is that the user’s ZIP code can then be automatically stored in the personalization provider and remembered every time that same user loads the page. Create a new application subfolder called Controls
and add a new web user control to it called ZipCodeSelector
. The ascx
code for this control is extremely simple:
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="ZipCodeSelector.ascx.cs" Inherits="Controls_ZipCodeSelector" %>
Zip Code: <asp:TextBox ID="txtZip" runat="server" />
<asp:Button ID="btnSetZip" runat="server" Text="Set" OnClick="btnSetZip_Click" />
The C# code that drives the control looks like this:
The PersonalizableAttribute
attribute class marks the ZipCode
property as one that is not only managed by the personalization provider, but in this case it also indicates that the ZipCode
property is managed at the User
scope.
Under the hood, when you place a Web Part on a page that has a ConnectionProvider
attribute on it, that tells the Web Part framework that the Web Part is publishing data.
To create a Web Part that consumes the data published by the ZipCodeSelector
control, add a new Web User Control to the Controls
folder and call it WeatherPart
. We’re not actually going to create a real weather control, so all you need to do is add the following code to your ascx
file:
Currently Displaying the Weather for <asp:Label ID="lblZip" runat="server" />
Then you can modify WeatherPart.ascx.cs
so that it contains the following code to consume a ZIP code:
The reason the preceding code uses the PreRender
event is because, as the developer, you can’t be absolutely sure when during the control’s life cycle the connection data will be transferred. So the safest bet is to use the last event in the control life cycle before rendering to process the data being shared over the connection to guarantee that the data has been delivered. You will find that if you use the standard Page_Load
method, the zipProvider
instance will be null
.
Build the solution to make sure everything compiles properly. Next, open up default.aspx
again and select the CatalogZone
control you placed in the designer earlier. Select the control’s context menu and then click Edit Templates. This will open up the inside of the DeclarativeCatalogPart
and allow you to drop additional controls into the catalog. Drag both of the controls created in this section into the area and then switch to design view to set the Title
property. The new DeclarativeCatalogPart
region should look something like this:
To allow users to modify the connection properties of connected Web Parts, you need a ConnectionsZone
, so drag one of those from the Toolbox into the third column of the table right below the EditorZone
and CatalogZone
.
Now you’re ready to run the application. When you run it, you will see that a new display mode, Connect, has been added to the display mode selector created earlier. Before using that mode, open the Catalog mode and add the two new Web Parts to the main zone. The ZIP code selector should contain an empty text box and the weather Web Part should display the “(no data)” phrase because it hasn’t been connected and isn’t receiving data.
Switch the page into Connect mode and click the drop-down menu for the ZIP code provider Web Part. Click the new Connect menu option. You will then be able to choose the destination control from a drop-down list of compatible controls. If there were 10 controls on the page that consumed ZIP codes using the IZipCode
interface, all 10 of them would appear in the drop-down list. A portion of the page containing the connection editor for the ZIP code provider Web Part is shown in Figure 26.5.
Figure 26.5 Connecting a provider to a consumer using a connections zone.
When you connect the Web Parts and switch back to the Browse mode of the page, you won’t notice any immediate difference because you still haven’t given the ZIP code provider part a ZIP code. Enter a ZIP code and click the Set button. As soon as you click that button, you should not only see that the ZIP code remained in the text box, but that the weather consumer part has received the ZIP code, as shown in Figure 26.6.
Finally, close the page and then reopen it. You will see that the ZIP code provider has remembered your ZIP code because of the attributes used on the ZipCode
property. As a result, that Web Part has also provided the ZIP code to the weather consumer part—all without you having to do any additional work.
Figure 26.6 Web part data provider and consumer in action.
This is a fairly dense chapter, packed full with information about Web Parts and the ASP.NET 2.0 Web Part framework. Throughout this chapter you learned what Web Parts are, how they work, and how you can deploy them on Web Part Pages. In addition, this chapter presented quite a bit of information about the extensive use of the personalization provider by the Web Parts framework and how you can make that work for you. This chapter is by no means the definitive reference for all things related to Web Parts, but it has provided you with enough information so that you can get started with Web Parts and you can make informed design decisions when presented with the opportunity to create a solution involving Web Parts.
3.133.116.126