The ASP.NET Web Part Framework enables you to build web applications that can be personalized by users at runtime. A Web Part application can be personalized by individual users or the application can be personalized by a single administrator for everyone.
You can take advantage of Web Parts to build personalizable portal applications like My Yahoo! (http://my.yahoo.com) or My MSN (http://my.msn.com). Users of these applications can customize both the content and appearance of the application by interacting with a web page. For example, you can select the content you want to see from categories of content such as News, Sports, and Weather (see Figure 27.1). You can also arrange the content on a page in the manner that is most relevant to you (see Figure 27.2).
Most large companies have internal website portals. You can take advantage of Web Parts to enable the individual employees of your company to customize the portal pages in the way that is most relevant to them. For example, a software tester might want a home page that displays a list of the most recent bugs. A marketing person, on the other hand, might want to see a news feed and stock ticker.
The Web Part Framework also can be used to build applications that can be customized by one or more administrators for everyone. Imagine, for example, that you want to build and sell a customized web store to your clients. If you build your application by using Web Parts, your clients can customize the application’s appearance from their browsers without any technical knowledge.
In this chapter, you are introduced to the Web Part Framework. You learn how to build simple Web Parts and add the Web Parts to different zones in a page. You also learn how to enable users to edit Web Part properties from a Web Form page. Finally, you learn how you can connect Web Parts to communicate information from one Web Part to another.
A Web Part is an ASP.NET control that is contained within a Web Part Zone. Any ASP.NET control can be used as a Web Part, including any standard ASP.NET control such as the GridView, Image, or LinkButton control. You can also create a Web Part by creating a new User control or a new custom Web control.
ASP.NET 2.0 Web Parts will be used in the next version of Windows Sharepoint Services (WSS) and Microsoft Office Sharepoint Portal Server (SPS). The good news is that if you develop Web Parts for the ASP.NET 2.0 Framework, then the Web Parts will work with the new versions of these products when they are released. The bad news is that ASP.NET 2.0 Web Parts are not compatible with the current implementation of Web Parts used in these two products.
Because you can create a new Web Part by creating a new control, a Web Part can do anything you want. You can create an Email Client Web Part, a Random Quotation of the Day Web Part, a Shopping Cart Web Part, or a Task List Web Part. Anything you can do in the ASP.NET Framework, you can do with Web Parts.
When you add an ASP.NET control to a Web Part Zone, the control automatically gets several special capabilities. For example, you can drag and drop a Web Part from one Web Part Zone to another. You can minimize and maximize a Web Part. You can modify the properties of a Web Part and the modifications are automatically saved.
Web Parts are just one type of control included in the Web Part Framework. You can use several different types of parts when building a Web Part page. You can also add several different types of zones to a Web Part page.
When you build a page that contains Web Parts, you divide the page into different zones. Each zone is responsible for managing and rendering a particular type of part. There are four standard types of zones included in the Web Part Framework:
Web Part Zones—. This type of zone is used to render Web Parts. You can add Web Parts to a Web Part Zone and drag and drop Web Parts between different Web Part Zones.
Editor Zones—. This type of zone is used to render Editor Parts. Use Editor Parts to enable a user to edit Web Part properties.
Catalog Zones—. This type of zone is used to render Catalog Parts. Use Catalog Parts to display lists of Web Parts that a user can add to a page.
Connections Zones—. This type of zone is used to display an interface that enables users to connect Web Parts dynamically.
You can extend the Web Part Framework with custom zones. We’ll explore this option in Chapter 30, “Extending the Web Part Framework.”
Every page that contains Web Parts contains at least one Web Part Zone. A Web Part Zone is used to lay out the Web Parts on a page.
The other types of zones are known collectively as tool zones. Adding a tool zone to a page is optional. If you don’t want a user to add new Web Parts to a page, then don’t include a Catalog Zone in the page. If you don’t want a user to be able to edit or connect Web Parts, then don’t add Editor or Connections Zones to a page.
By default, when you first open a page that contains Web Parts, the only type of zone that is rendered is Web Part Zones. To display the other types of zones, you must change the page’s Display Mode.
At any time, a page can be in one of the following Display Modes:
Browse—. The default mode. In this mode, you cannot rearrange or edit Web Parts.
Design—. In this mode, you can drag and drop Web Parts from one Web Part Zone to another.
Edit—. In this mode, you can edit a Web Part’s properties by using one or more Editor Parts.
Catalog—. In this mode, you can add new Web Parts to a page from one or more Catalog Parts.
Connect—. In this mode, you can create dynamic connections between Web Parts.
A page that contains Web Parts can be in only one Display Mode at a time. If you switch to Edit Display Mode, then the contents of any Editor Zones are rendered and you can edit Web Parts. If you switch to Catalog Display Mode, then the contents of any Catalog Zones are rendered and you can add new Web Parts. However, you cannot set a page to both Edit and Catalog Display Mode at the same time.
You can extend the Web Part Framework with custom Display Modes. We’ll explore this option in Chapter 30.
When a user makes changes to a Web Part’s properties, the Web Part Framework automatically saves these changes. For example, a user can add one or more Web Parts to a page and arrange the Web Parts with a particular layout. If the user returns to the page in the future, the Web Parts will remember the layout. This feature of the Web Part Framework is called personalization.
The Web Part Framework supports two types of personalization: User and Shared. By default, all changes made to a Web Parts page have User scope. Changes are scoped to a particular user, which enables each user to personalize the same page in different ways.
The Web Part Framework also supports Shared scope personalization. An administrator of a Web Part application can make changes that have an effect on everyone who uses the application. For example, an administrator might want to add a standard set of Web Parts to a page and prevent individual users from removing them.
This chapter sticks to User scope personalization. In Chapter 29, “Personalizing Web Parts,” the topic of User and Shared scope personalization is examined in detail.
For personalization to work, the Web Part Framework must have a method of identifying users. The default personalization provider included with the Web Part Framework requires that users be authenticated. If you use the default provider, then an unauthenticated user can browse, but not customize, a Web Part application. (In Chapter 29, you learn how to create a custom personalization provider.)
You must enable authentication for your application for many of the sample pages in this chapter to work. By default, Windows Authentication is enabled. For more information about enabling authentication, see Chapter 20, “Using the Login Controls.”
Let’s get our hands dirty by building a simple Web Part application. In this section, you’ll create a minimal Web Part application that consists of a single page. It illustrates how to use three of the different types of zones: Web Part Zones, Editor Zones, and Catalog Zones.
You start by creating two painfully simple Web Parts. The easiest way to create new Web Parts is to create User Controls. The User Controls contained in Listing 27.1 and Listing 27.2 serve as the Web Parts.
To learn more about User Controls, see Chapter 7, “Creating Custom Controls with User Controls.”
These simple Web Parts both consist of nothing more than a single line of text. You can, of course, create more complicated Web Parts with User controls. For example, you can create a User control that contains a GridView control bound to some database data. Or, you can create a User Control that calls a remote web service to display the current weather. In this section, however, we keep things simple.
Next, you need to create the page that you’ll use to host your Web Parts. Every page that contains Web Parts must, at a minimum, have one WebPartManager control and one or more WebPartZone controls.
Every page that contains Web Parts must include one, and only one, WebPartManager control. The WebPartManager control is responsible for tracking the state of all the Web Parts on the page. The WebPartManager control must appear before any other Web Parts on the page. For this reason, it is a good idea to place the WebPartManager control immediately after the server-side form control in the page.
The WebPartZone controls are used to mark the different areas of the page that can contain Web Parts. They are used to lay out Web Parts on a page. You can add as many WebPartZone controls to a page as you want.
You can add the WebPartManager control and the WebPartZone controls to a Master Page. This is useful when you want to automatically include a WebPartManager and WebPartZone controls in multiple content pages without explicitly declaring the controls in each page.
You’ll build the page in stages. First, create a page that contains a WebPartManager control and two Web Part Zone controls (see Listing 27.3).
Example 27.3. SimpleWebParts1.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:40%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } html { background-color:#eeeeee; } </style> <title>Simple Web Parts 1</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> </form> </body> </html>
Notice that the page in Listing 27.3 contains a WebPartManager control immediately after the server-side <form>
tag. If you neglected to add the WebPartManager control to the page, you would get an exception when you opened the page.
The page also contains two Web Part Zones. The first Web Part Zone contains the two simple Web Parts that you created earlier. The Web Parts are listed in the WebPartZone control’s ZoneTemplate. The second Web Part Zone is empty.
Notice that the two simple Web Parts are both provided with a Title and Description attribute. The Title attribute appears in the Web Part’s title bar, and the description appears as a tool tip when you hover your mouse over a Web Part.
If you open the page in Listing 27.3 in Source View, you’ll notice a green squiggle warning beneath the Title and Description attributes. You can safely ignore this warning. The warning appears because these aren’t really properties of the User Controls. Technically, the Title and Description properties are expando properties that are interpreted by the Web Part Framework at runtime.
To keep things simple, the two User controls are registered with the <%@ Register %>
directive at the top of the page. Another option would be to register the User Controls in your application’s Web Configuration file and make the controls automatically available in any page in your application. To learn more about User controls see Chapter 7.
When you open the page in Listing 27.3 in a browser, you see the page in Figure 27.3. At the moment, you can’t do very much with the page. The only thing you can do is open each of the Web Part’s menus. Each Web Part menu has two options: Minimize and Close. Minimizing a Web Part shrinks a Web Part to its title bar. If you close a Web Part, then the Web Part is no longer rendered to the page.
The page in Listing 27.3 uses an internal Cascading Style Sheet to position the two Web Part Zones. The zones are positioned with a liquid layout. Both Web Part Zones are floated to the left with the help of a CSS class named column.
You can, of course, lay out the Web Part Zones in a page by using an HTML table. However, you should feel very guilty about even thinking about doing it because you should strive to use HTML tables only when displaying tabular data and not for layout.
How do you open a Web Part after you close it? You use the PageCatalogPart control that is discussed later in this section.
If you prefer, you can prevent users from closing Web Parts by disabling the Close menu option. Set the CloseVerb-Visible
property on the WebPartZone control to the value false.
To do anything interesting in a page that contains Web Parts, you need to add a mechanism to the page that enables users to switch between different Web Part Display Modes. The WebPartManager control is responsible for setting the Display Mode. You can set the Display Mode by taking advantage of the WebPartManager control’s DisplayMode
property like this:
WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode
This line of code sets the page to Design Display Mode. Each of the standard Web Part Display Modes is represented by a shared (static) field exposed by the WebPartManager class. (Display Modes are not represented by an enumeration because you can create custom Display Modes.)
Here’s another method of setting the Display Mode:
WebPartManager1.DisplayMode = WebPartManager1.DisplayModes("Design")
This line of code also sets the page Display Mode to Design Display Mode. However, in this case, the DisplayModes
property is used as the value of the assignment. The DisplayModes
property exposes a collection of all the Display Modes that the WebPartManager control knows. We’ll use this second method of setting the Display Mode because it makes it possible to avoid using a Visual Basic SELECT...CASE
statement.
The page in Listing 27.4 is the same as the previous page in Listing 27.3 with one addition. This new page contains an ASP.NET menu control that enables you to switch the Display Mode of the page to Design Display Mode. (The modifications are emphasized in bold.)
Example 27.4. SimpleWebParts2.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(sender As Object, e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:40%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Simple Web Parts 2</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> </form> </body> </html>
After you open the page in Listing 27.4, you can click the Design menu option and drag and drop the Web Parts between the two Web Part Zones (see Figure 27.4). When you set a page to be in Design Display Mode, the Web Part Framework automatically generates the necessary client-side JavaScript code for moving Web Parts.
Performing a drag-and-drop operation requires using a mouse. This requirement violates Section 508 and WCAG accessibility guidelines because a person with limited mobility might need to interact with a web page from the keyboard. You can satisfy these accessibility requirements by adding a LayoutEditorPart control to the page. The LayoutEditorPart control enables you to move Web Parts around a page without using a mouse.
It is important to understand that the Web Part Framework automatically saves the state of all the Web Parts in a page. In other words, if you rearrange the Web Parts, the Web Parts retain their new positions when you return to the page in the future.
In this section, I’m assuming that Windows Authentication is enabled for your application (which is the default Authentication mode). If your Web Parts are forgetting their positions on a page after you close and re-open the page then, most likely, you are not being authenticated. For more information on configuring Authentication, see Part VI, “Security,” of this book.
You can also enable users to add new Web Parts to a page. To do this, you need to add a CatalogZone control that contains one or more Catalog Parts to the page. For example, the page in Listing 27.5 includes a Declarative Catalog Part which lists both the FirstSimplePart and SecondSimplePart Web Parts.
Example 27.5. SimpleWebParts3.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Simple Web Parts 3</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server" /> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:CatalogZone id="CatalogZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart id="DeclarativeCatalogPart" Runat="server"> <WebPartsTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </WebPartsTemplate> </asp:DeclarativeCatalogPart> <asp:PageCatalogPart id="PageCatalogPart1" Runat="server" /> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html>
The additions to Listing 27.5 are emphasized in bold. Notice that a new menu option has been added to the ASP.NET Menu control. The new menu option enables you to switch the page to Catalog Display Mode (see Figure 27.5).
Furthermore, a Catalog Zone has been added to the page. The Catalog Zone includes a DeclarativeCatalogPart which is used to list the two Web Parts that you can add to the page. The CatalogZone also includes a PageCatalogPart control, which is used to add closed Web Parts back to a page.
After you open the page in Listing 27.5 in a browser, you can click the Catalog menu option and add new instances of the two Web Parts to the page. Again, any changes you make to the page are saved automatically by the Web Part Framework.
Notice that you can now retrieve any Web Parts that you have closed on the page by taking advantage of the PageCatalogPart. If you close a Web Part by selecting a Web Part’s Close menu option, you can re-open the Web Part by clicking Catalog and selecting the closed Web Part from the list of Web Parts rendered by the Page Catalog Part control.
The DeclarativeCatalogPart control does not enable you to drag and drop Web Parts onto the page. If you want to add drag-and-drop support or paging and sorting support or any other custom functionality to a Catalog Part, then you need to create a custom Catalog Part. This option is discussed in Chapter 30.
Finally, you can enable users to edit Web Parts. For example, Listing 27.6 contains a new Web Part named FeaturedBookPart. This Web Part displays information about a particular book.
Example 27.6. FeaturedBookPart.ascx
<%@ Control Language="VB" ClassName="FeaturedBookPart" %> <script runat="server"> Private _bookTitle As String = "Untitled" Private _category As BookCategory = BookCategory.Computers Private _bookDescription As String Private _onSale As Boolean Public Enum BookCategory Computers History Mystery End Enum <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("Title")> _ <WebDescription("The title of the book")> _ Public Property BookTitle() As String Get Return _bookTitle End Get Set(ByVal Value As String) _bookTitle = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("Category")> _ <WebDescription("The category of the book")> _ Public Property Category() As BookCategory Get Return _category End Get Set(ByVal Value As BookCategory) _category = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("Description")> _ <WebDescription("The description of the book")> _ Public Property BookDescription() As String Get Return _bookDescription End Get Set(ByVal Value As String) _bookDescription = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("On Sale")> _ <WebDescription("Indicates that the book is on sale")> _ Public Property OnSale() As Boolean Get Return _onSale End Get Set(ByVal Value As Boolean) _onSale = value End Set End Property Private Sub Page_PreRender() ltlBookTitle.Text = _bookTitle lblCategory.Text = _category.ToString() lblBookDescription.Text = _bookDescription lblOnSale.Visible = _onSale End Sub </script> <h1 class="bookTitle"> <asp:Literal ID="ltlBookTitle" runat="server"/> </h1> <asp:Label ID="lblCategory" CssClass="category" runat="server" /> <br /> <asp:Label ID="lblBookDescription" runat="server" /> <br /> <asp:Label ID="lblOnSale" Text="On Sale!" Visible="false" CssClass="onSale" runat="server" />
You should notice several things about the Web Part in Listing 27.6. Notice that each of its properties is decorated with the following attributes: Personalizable, WebBrowsable, WebDisplayName, WebDescription. The Web Part Framework automatically detects these attributes.
The most important attribute is the Personalizable attribute. Any property marked with the Personalizable attribute is automatically saved and loaded by the Web Part Framework. Because the BookTitle, BookCategory, BookDescription, and OnSale properties are all marked as Personalizable, any changes to these properties are saved by the Web Part Framework.
The remaining three attributes—WebBrowsable, WebDisplayName, and WebDescription—are used by the PropertyGridEditorPart control. Only properties marked with the WebBrowsable attribute are displayed in the property grid rendered by the PropertyGridEditorPart control. The WebDisplayName and WebDescription attributes determine the title and description displayed for the property in the property sheet. Both the WebDisplayName and WebDescription attributes are optional.
The page in Listing 27.7 illustrates how you can edit the FeaturedBookPart by using the PropertyGridEditorPart control (changes from the previous listings are emphasized in bold).
Example 27.7. SimpleWebParts4.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FeaturedBookPart" Src="~/FeaturedBookPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } .bookTitle { font:bold 14px Arial,Sans-Serif; border-bottom:solid 1px black; } .category { font:italic 12px Arial,Sans-Serif; } .onSale { font:bold 14px Arial,Sans-Serif; background-color:yellow; } </style> <title>Simple Web Parts 4</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Edit" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FeaturedBookPart id="FeaturedBookPart1" Title="Featured Book" Description="Displays featured book" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:EditorZone id="EditorZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:PropertyGridEditorPart id="PropertyGridEditorPart1" Runat="server" /> </ZoneTemplate> </asp:EditorZone> </form> </body> </html>
When you open the page in Listing 27.7 in a browser, you can click the Edit menu option to switch the page into Edit Display Mode. When a page is in Edit Display Mode, you can edit particular Web Parts by selecting the Edit menu option from a Web Part menu. Selecting a Web Part to edit causes the EditorZone to render the PropertyGridEditorPart control (see Figure 27.6).
Notice that form fields are automatically generated for each of the properties that were marked as Personalizable. If you modify any of the properties and click either OK or Apply, the Web Part Framework automatically saves any changes to the properties.
By default, changes to a Web Part property have User scope. In other words, each person who uses a Web Part page can customize it for his or her particular needs. You can also enable Shared scope personalization. In that case, changes to a Web Part property have an effect on all users. To learn more about personalization, see Chapter 29, “Personalizing Web Parts.”
The PropertyGridEditorPart automatically generates a form that is accessible to persons with disabilities. The form is contained in a fieldset element. Furthermore, label elements with for
attributes are used to explicitly associate each label with each form field.
This section has walked you through the process of creating a basic page that contains Web Parts. The remainder of this chapter examines each of the tool zones included in the Web Part Framework in more detail. You’ll learn how to work with Catalog Zones, Editor Zones, and Connections Zones.
You use a Catalog Zone to list one or more catalogs of Web Parts that you can add to the page. The contents of a Catalog Zone appear only when a page is in Catalog Display Mode.
There are three standard types of Catalog Part controls included in the Web Part Framework: Declarative Catalog Parts, Page Catalog Parts, and Import Catalog Parts.
A Declarative Catalog Part contains a static list of controls that you can add to a page. You can supply the list of controls in two ways: The controls can be listed in the DeclarativeCatalogPart
control’s <WebPartsTemplate>
tag or you can list the Web Parts in an external file.
The page in Listing 27.8 illustrates how you can list the Web Parts displayed in the Declarative Catalog Part inline.
Example 27.8. DeclarativeCatalogPart1.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Declarative Catalog Part 1</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server" /> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:CatalogZone id="CatalogZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart id="DeclarativeCatalogPart" Runat="server"> <WebPartsTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </WebPartsTemplate> </asp:DeclarativeCatalogPart> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html>
The page in Listing 27.8 contains a CatalogZone
control. The CatalogZone
control contains a ZoneTemplate
, which includes the DeclarativeCatalogPart
control. Finally, the DeclarativeCatalogPart
control has a WebPartsTemplate
that lists two Web Parts: the FirstSimplePart
and SecondSimplePart
.
If you open the page in your browser and click the Catalog menu link, you can see the list of controls rendered by the DeclarativeCatalogPart
control. You can add a new part to the page by selecting any of the parts in the list, selecting a Web Part Zone from the drop-down list, and clicking the Add button (see Figure 27.7).
The DeclarativeCatalogPart
does not support paging or sorting. In Chapter 30, “Extending the Web Part Framework,” you learn how to create custom CatalogPart
controls that support more functionality.
If you want to enable users to personalize multiple pages in an application, then it doesn’t make sense to list the Web Parts displayed by a Declarative Catalog Part in each page. You can use the DeclarativeCatalogPart
control’s WebPartsListUserControlPath
property to point to an external file that contains a list of Web Parts.
The DeclarativeCatalogPart
in Listing 27.9 uses the WebPartsListUserControlPath
property. The file that contains the list of Web Parts is contained in Listing 27.10. (Notice that the file is a User Control.)
Example 27.9. DeclarativeCatalogPart2.aspx
<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Declarative Catalog Part 2</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server" /> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:CatalogZone id="CatalogZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart id="DeclarativeCatalogPart" WebPartsListUserControlPath="~/WebPartList.ascx" Runat="server" /> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html>
Example 27.10. WebPartList.ascx
<%@ Control Language="VB" ClassName="WebPartList" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" />
Notice that the FirstSimplePart
and SecondSimplePart
controls are not registered in the page in Listing 27.9. However, you do need to register the controls in the file in Listing 27.10.
You can mix the Web Parts retrieved from an external file and the Web Parts declared inline. The Web Parts retrieved from the two sources are combined into one list.
The PageCatalogPart
control displays all the Web Parts in the current page that have been closed. The control enables users to add closed Web Parts back to the original page.
There is a difference between closing a Web Part and deleting a Web Part. You cannot delete a Web Part that is declared in a page, but you can close it. Furthermore, when you delete a Web Part from a page, all personalization state information is lost. When you close a Web Part, on the other hand, personalization data is not lost.
The page in Listing 27.11 demonstrates how you can use the PageCatalogPart
control in a Catalog Zone.
Example 27.11. ShowPageCatalogPart.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %>`1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Page Catalog Part</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:CatalogZone id="CatalogZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:PageCatalogPart id="PageCatalogPart1" Runat="server" /> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html>
After you open the page in Listing 27.11, you see two Web Parts in the left column Web Part Zone. You can close either Web Part by selecting Close from the Web Part’s menu. If you click the Catalog link, you can open the Page Catalog and add any closed Web Parts back to the page (see Figure 27.8).
If you need to transfer a Web Part control’s settings between two different pages, or even between two different applications, you can export the Web Part from one page and import the Web Part on another page.
When you export a Web Part, an XML file that represents the Web Part’s properties is generated. You can download and save the settings file to your local computer. After you export the settings file, you can import the settings to any Web Part application that includes an Import Catalog Part and knows about the type of Web Part control that you are importing. When you import a Web Part, a new instance of the Web Part control is created that contains the original settings.
You can programmatically export and import Web Parts by using the WebPartManager
control’s ExportWebPart()
and ImportWebPart()
methods.
Before you can export any Web Parts from a page, you must enable exporting for your application. The web configuration file in Listing 27.12 contains the necessary configuration settings.
To make things more interesting, we’ll create a new Web Part to illustrate how exporting a Web Part works. The new Web Part represents a user profile. It displays both sensitive and non-sensitive data. The ProfilePart
is contained in Listing 27.13.
Example 27.13. ProfilePart.ascx
<%@ Control Language="VB" ClassName="ProfilePart" %> <script runat="server"> Private _firstName As String Private _lastName As String Private _socialSecurityNumber As String Private _userProfile As String <Personalizable()> _ <WebBrowsable()> _ Public Property FirstName() As String Get Return _firstName End Get Set(ByVal Value As String) _firstName = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ Public Property LastName() As String Get Return _lastName End Get Set(ByVal Value As String) _lastName = value End Set End Property <Personalizable(PersonalizationScope.User, True)> _ <WebBrowsable()> _ Public Property SocialSecurityNumber() As String Get Return _socialSecurityNumber End Get Set(ByVal Value As String) _socialSecurityNumber = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ Public Property UserProfile() As String Get Return _userProfile End Get Set(ByVal Value As String) _userProfile = value End Set End Property Private Sub Page_PreRender() lblFirstName.Text = _firstName lblLastName.Text = _lastName lblSocialSecurityNumber.Text = _socialSecurityNumber lblUserProfile.Text = _userProfile End Sub </script> First Name: <asp:Label id="lblFirstName" Runat="server" /> <br /> Last Name: <asp:Label id="lblLastName" Runat="server" /> <br /> Social Security Number: <asp:Label id="lblSocialSecurityNumber" Runat="server" /> <br /> User Profile: <asp:Label id="lblUserProfile" Runat="server" />
The ProfilePart
displays four profile properties: a person’s First Name, Last Name, Social Security Number, and User Profile. The value of the Social Security Number property is considered to be sensitive data and the values of the other properties are not.
Notice that all four properties in Listing 27.13 are decorated with the Personalizable attribute. Only properties marked with this attribute can be exported.
Furthermore, notice that the Personalizable attribute associated with the SocialSecurityNumber
property includes two parameters. The second parameter represents whether or not the property contains sensitive data. To prevent the Social Security Number from being exported, this parameter is set to the value True
.
The page in Listing 27.14 illustrates how you can use the ProfilePart
in a page.
Example 27.14. ShowImportCatalogPart.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="ProfilePart" Src="~/ProfilePart.ascx" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Import Catalog Part</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> <asp:MenuItem Text="Edit" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:ProfilePart id="ProfilePart1" Title="Profile Part" Description="Displays your profile" ExportMode="NonSensitiveData" Runat="server" /> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:CatalogZone id="CatalogZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:ImportCatalogPart id="ImportCatalogPart1" Runat="server" /> </ZoneTemplate> </asp:CatalogZone> <asp:EditorZone id="EditorZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:PropertyGridEditorPart id="PropertyGridEditorPart1" Runat="server" /> </ZoneTemplate> </asp:EditorZone> </form> </body> </html>
In Listing 27.14, the ProfilePart
is declared in the first Web Part Zone. Notice that the ProfilePart
includes an ExportMode
property. This property can have three possible values:
None
—. The default value is to prevent users from exporting a Web Part.
All
—. This value enables users to export both sensitive and non-sensitive data.
NonSensitiveData
—. This value enables users to export only data that has not been marked as sensitive.
The first thing that you should do after opening the page in Listing 27.14 is to create a user profile. Click the Edit link to switch the page to Edit Display Mode. Select the Edit menu option on the ProfilePart and enter values for the ProfilePart control’s properties. Click the OK button when you are finished.
Next, you can export the ProfilePart
by selecting Export from the ProfilePart
control’s menu (see Figure 27.9). When you export the ProfilePart, an XML file resembling the file in Listing 27.15 is downloaded to your computer.
Example 27.15. ProfilePart.WebPart
<?xml version="1.0" encoding="utf-8"?> <webParts> <webPart> <metaData> <type src="~/ProfilePart.ascx" /> <importErrorMessage>Cannot import this Web Part.</importErrorMessage> </metaData> <data> <properties> <property name="LastName" type="string">Walther</property> <property name="FirstName" type="string">Ruth</property> <property name="UserProfile" type="string">I like ASP.NET 2.0!</property> </properties> <genericWebPartProperties> <property name="AllowClose" type="bool">True</property> <property name="Width" type="unit" /> <property name="AllowMinimize" type="bool">True</property> <property name="AllowConnect" type="bool">True</property> <property name="ChromeType" type="chrometype">Default</property> <property name="TitleIconImageUrl" type="string" /> <property name="Description" type="string">Displays your profile</property> <property name="Hidden" type="bool">False</property> <property name="TitleUrl" type="string" /> <property name="AllowEdit" type="bool">True</property> <property name="Height" type="unit" /> <property name="HelpUrl" type="string" /> <property name="Title" type="string">Profile Part</property> <property name="CatalogIconImageUrl" type="string" /> <property name="Direction" type="direction">NotSet</property> <property name="ChromeState" type="chromestate">Normal</property> <property name="AllowZoneChange" type="bool">True</property> <property name="AllowHide" type="bool">True</property> <property name="HelpMode" type="helpmode">Navigate</property> <property name="ExportMode" type="exportmode">NonSensitiveData</property> </genericWebPartProperties> </data> </webPart> </webParts>
Notice that the file in Listing 27.15 does not include the Social Security Number property. However, it does include the First Name, Last Name, and User Profile properties.
After you download the XML file, you can import the Web Part represented by the XML file into another Web Part page or another Web Part application. Click the Catalog link to switch to Catalog Display Mode. The Import Catalog Part enables you to upload a Web Part settings file.
After you upload the settings file, the Web Part represented by the file is listed by the Import Catalog Part. You can add the ProfilePart to any Web Part Zone (see Figure 27.10).
You use an Editor Zone to enable users to edit the Web Parts contained in a page. An Editor Zone can contain one or more Editor Parts. The contents of an Editor Zone are displayed only when the page is in Edit Display Mode.
The Web Part Framework includes four standard Editor Parts: the AppearanceEditorPart
, the BehaviorEditorPart
, the LayoutEditorPart
, and the PropertyGridEditorPart
. This section discusses each of these Editor Parts.
You can create your own Editor Parts. This option is explored in Chapter 30, “Extending the Web Part Framework.”
The AppearanceEditorPart
control is useful for an administrator of a Web Part application, who can use the part to modify the general appearances of the Web Parts in the application (see Figure 27.11). This control enables you to modify the following properties of a Web Part:
Title
—. The title displayed for a Web Part in the Web Part title bar.
ChromeType
—. The type of chrome rendered around a Web Part. Possible values are Default, TitleAndBorder
, TitleOnly
, BorderOnly
, and None.
Direction
—. The direction that text is displayed in a Web Part. This property is useful when working with languages that are written from right to left, such as Arabic.
Height
—. The pixel height of the Web Part.
Width
—. The pixel width of the Web Part.
Hidden
—. When true, the Web Part is not displayed in a browser. The Web Part is rendered with a display:hidden
Cascading Style Sheet property.
The page in Listing 27.16 illustrates how you can add the AppearanceEditorPart
to an Editor Zone.
Example 27.16. ShowAppearanceEditorPart.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Appearance Editor Part</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Edit" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:EditorZone id="EditorZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:AppearanceEditorPart id="AppearanceEditorPart1" Runat="server" /> </ZoneTemplate> </asp:EditorZone> </form> </body> </html>
After you open the page in Listing 27.16, you can view the Appearance Editor Part by clicking the page menu’s Edit link, and then selecting Edit from either of the two Web Part control menus.
The Behavior Editor Part can be used to modify properties of a Web Part that have Shared personalization scope. In other words, it can be used to modify the properties that appear for all users and not only the current user.
The Behavior Editor Part enables you to modify the following properties:
Description
—. Enables you to set the Web Part description that appears as a tooltip when you hover your mouse over a Web Part.
Title Link
—. Enables you to convert the title of a Web Part into a hyperlink to a page.
Title Icon Image Link
—. Enables you to specify an image that appears in a Web Part title bar.
Catalog Icon Image Link
—. Enables you to specify an image that appears when a Web Part is listed in a Catalog Part.
Help Link
—. Enables you to add a Help menu item that links to a help page.
Help Mode
—. Enables you to specify how the help window appears when you select a Web Part’s Help menu option. Possible values are Modal, Modeless, and Navigate.
Import Error Message
—. Enables you to specify the error text that appears when a Web Part is imported with an ImportCatalogPart
control that fails.
Export Mode
—. Enables you to specify whether a Web Part can be exported. Possible values are Do Not Allow, Export All Values, and Non-Sensitive Data Only.
Authorization Filter
—. Enables you to specify a string that can be used to determine whether a Web Part can be added to a page.
Allow Close
—. Enables you to prevent users from closing a Web Part.
Allow Connect
—. Enables you to specify whether a user is allowed to connect the current Web Part to another Web Part.
Allow Edit
—. Enables you to specify whether a Web Part can be edited.
Allow Hide
—. Enables you to specify whether a user can hide a Web Part (render the Web Part, but not display it).
Allow Minimize
—. Enables you to specify whether a user is allowed to minimize a Web Part.
Allow Zone Change
—. Enables you to specify whether a user is allowed to drag and drop the Web Part to a new location.
The Behavior Editor Part appears only when Shared personalization scope has been enabled for the page. You’ll learn the gritty details of Shared personalization scope in Chapter 29, “Personalizing Web Parts.” Right now, however, it is enough to know that there are two requirements for placing a page into Shared personalization scope.
First, you need to add the web configuration file in Listing 27.17 to your application.
Example 27.17. Web.Config
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <webParts> <personalization> <authorization> <allow users="*" verbs="enterSharedScope"/> </authorization> </personalization> </webParts> </system.web> </configuration>
The Web Configuration file in Listing 27.17 authorizes all users to enter Shared personalization scope (the asterisk represents everyone). Normally, you want to restrict this privilege to the administrators of your application.
Next, you need to place the current page in Shared personalization scope. One way to do this is to use the Personalization property of the WebPartManager
control, like this:
<asp:WebPartManager
id="WebPartManager1"
Personalization-InitialScope="Shared"
Runat="server" />
The Personalization-InitialScope
attribute causes the page to enter Shared personalization scope for users who are authorized by the web configuration file to enter Shared personalization scope. If a user is not authorized, the attribute is ignored.
The page in Listing 27.18 illustrates how you can add a BehaviorEditorPart
control to an EditorZone
.
Example 27.18. ShowBehaviorEditorPart.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Behavior Editor Part</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Personalization-InitialScope="Shared" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Edit" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:EditorZone id="EditorZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:BehaviorEditorPart id="BehaviorEditorPart1" Runat="server" /> </ZoneTemplate> </asp:EditorZone> </form> </body> </html>
After you open the page in Listing 27.18 in your web browser, you can click the Edit menu link to place the page in Edit Display Mode. Next, select the Edit menu option on one of the two Web Parts, which causes the Behavior Editor Part to appear (see Figure 27.12).
The Layout Editor Part enables you to arrange Web Parts on a page without using a mouse (see Figure 27.13). You should always include a Layout Editor Part in every Web Parts page for two reasons.
First, adding a Layout Editor Part to a page makes your web application more accessible to persons with disabilities. Many persons with disabilities must interact with websites by using the keyboard. For example, if you are blind, then you will not be using a mouse to drag Web Parts around a page.
Both the Section 508 and WCAG 1.0 standards include guidelines concerned with the importance of creating device-independent pages.
Second, the Web Part Framework does not support drag-and-drop for browseers other than Internet Explorer. In particular, you cannot drag-and-drop Web parts when using Firefox or Opera. The Layout Editor Part provides you with an (imperfect) method of supporting browseres other than Internet Explorer.
The LayoutEditorPart control enables users to modify the following three properties:
Chrome State
—. Enables users to specify whether a Web Part is minimized or maximized.
Zone
—. Enables users to select a zone where they want a Web Part to be placed.
Zone Index
—. Enables users to specify the location of a Web Part within a zone.
The page in Listing 27.19 illustrates how you can add a LayoutEditorPart
control to an Editor Zone.
Example 27.19. ShowLayoutEditorPart.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FirstSimplePart" Src="~/FirstSimplePart.ascx" %> <%@ Register TagPrefix="user" TagName="SecondSimplePart" Src="~/SecondSimplePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Layout Editor Part</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Edit" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FirstSimplePart id="FirstSimplePart1" Title="First Web Part" Description="Our first simple Web Part" Runat="server" /> <user:SecondSimplePart id="SecondSimplePart1" Title="Second Web Part" Description="Our second simple Web Part" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:EditorZone id="EditorZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:LayoutEditorPart id="LayoutEditorPart1" Runat="server" /> </ZoneTemplate> </asp:EditorZone> </form> </body> </html>
When you open the page in Listing 27.19 in a web browser, you can click the Edit link to place the page into Edit Display Mode. Next, select the Edit menu option from any Web Part menu to see the Layout Editor Part.
The PropertyGridEditorPart
control enables users to modify custom properties of a Web Part control through a form interface. This control automatically generates a property sheet for a Web Part (see Figure 27.14).
If you want to be able to modify a particular Web Part property with the PropertyGridEditorPart
, then you must decorate the property with two attributes. First, you must add a Personalizable
attribute to the property. The Web Part Framework automatically saves any property decorated with the Personalizable
attribute.
Second, you must add a WebBrowsable
attribute to the property. The WebBrowsable
attribute is for the benefit of the PropertyGridEditorPart
control. The control displays only properties decorated with this attribute.
The Web Part in Listing 27.20, the FeaturedMoviePart
illustrates how to use both of these attributes.
Example 27.20. FeaturedMoviePart.ascx
<%@ Control Language="VB" ClassName="FeaturedMoviePart" %> <script runat="server"> Public Enum MovieCategory Action Animation Drama Horror End Enum Private _movieTitle As String Private _category As MovieCategory Private _movieDescription As String Private _inTheaters As Boolean <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("Title")> _ <WebDescription("The title of the movie")> _ Public Property MovieTitle() As String Get Return _movieTitle End Get Set(ByVal Value As String) _movieTitle = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("Category")> _ <WebDescription("The movie category")> _ Public Property Category() As MovieCategory Get Return _category End Get Set(ByVal Value As MovieCategory) _category = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("Description")> _ <WebDescription("The movie description")> _ Public Property MovieDescription() As String Get Return _movieDescription End Get Set(ByVal Value As String) _movieDescription = value End Set End Property <Personalizable()> _ <WebBrowsable()> _ <WebDisplayName("In Theaters")> _ <WebDescription("Is the movie currently showing?")> _ Public Property InTheaters() As Boolean Get Return _inTheaters End Get Set(ByVal Value As Boolean) _inTheaters = value End Set End Property Private Sub Page_PreRender() lblMovieTitle.Text = _movieTitle lblCategory.Text = _category.ToString() lblMovieDescription.Text = _movieDescription lblInTheaters.Visible = _inTheaters End Sub </script> <asp:Label id="lblMovieTitle" Runat="server" /> <br /> <asp:Label id="lblCategory" Runat="server" /> <br /> <asp:Label id="lblMovieDescription" Runat="server" /> <br /> <asp:Label id="lblInTheaters" Text="In Theaters Now!" CssClass="inTheaters" Runat="server" />
Notice that each of the properties of the FeatureMoviePart
in Listing 27.20 is marked with four attributes. Each property includes the required Personalizable
and WebBrowsable
attributes. In addition, the WebDisplayName
and WebDescription
attributes are used to provide each property with a name and description in the property sheet.
The page in Listing 27.21 demonstrates how you can use the PropertyGridEditorPart
control to edit the properties of the FeaturedMoviePart
.
Example 27.21. ShowPropertyGridEditorPart.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="FeaturedMoviePart" Src="~/FeaturedMoviePart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Property Grid Editor Part</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Edit" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:FeaturedMoviePart id="FeaturedMoviePart1" Title="Featured Movie Part" Description="Displays movie information" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:EditorZone id="EditorZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:PropertyGridEditorPart id="PropertyGridEditorPart1" Runat="server" /> </ZoneTemplate> </asp:EditorZone> </form> </body> </html>
After you open the page in Listing 27.21, you can click the Edit link to switch the page to Edit Display Mode. Next, select the Edit menu option on the FeaturedMoviePart
and you will see the property sheet rendered by the PropertyGridEditorPart
.
The PropertyGridEditorPart
automatically associates certain types of properties with certain types of form fields in the property sheet:
Boolean Property—. Displayed with a CheckBox
control.
Enumeration Property—. Displayed with a DropDownList
control.
Other Properties—. Displayed with a TextBox
control.
In the case of the FeaturedMoviePart
, The PropertyGridEditorPart
control renders a TextBox
control for the MovieTitle
property, a DropDownList
control for the Category
property, a TextBox
for the Description
property, and a CheckBox
control for the InTheaters
property.
The PropertyGridEditorPart
does not provide you with very much control over the appearance of the property sheet. For example, there is no way to specify the order of the form fields. If you want more control, then you need to create a custom EditorPart
. This option in discussed Chapter 30, “Extending the Web Part Framework.”
You can share information between two or more Web Parts on a page by connecting the Web Parts. There are a variety of different situations in which you might want to communicate information between two Web Parts.
For example, imagine that you are creating a Web Part application for a human resources department. You could create one Web Part that enables you to select a current employee. Another Web Part might display insurance information for the selected employee. Yet another Web Part might display information about the selected employee’s work history. If you connect all the Web Parts, then you can select a new employee from the first Web Part to see detailed information about the employee with the other two Web Parts.
Or, imagine that you are building a blog application with Web Parts. One Web Part might display a calendar. A second Web Part might display a list of blog entries. If you connect the two Web Parts, you can select a date in the calendar Web Part to see a list of matching entries in the blog Web Part.
When you connect two Web Parts, you create a connection between a provider Web Part and a consumer Web Part. The provider Web Part provides the information that is retrieved by the consumer Web Part. Multiple consumer Web Parts can be connected to the same provider.
You must follow a certain sequence of steps whenever you connect two Web Parts:
Create an interface that represents the information being shared.
Add the ConnectionProvider
attribute to a method of the provider Web Part.
Add the ConnectionConsumer
attribute to a method of the consumer Web Part.
Before you can communicate information between two Web Parts, you must specify an interface that describes the information being shared. An interface can contain a list of properties, methods, and events.
Next, the provider Web Part must have a method that returns a class that implements the interface. You mark the method that provides the interface by decorating the method with the ConnectionProvider
attribute.
Finally, the consumer Web Part must have a method that retrieves the interface. This method is marked in the consumer Web Part with the ConnectionConsumer
attribute.
Let’s go ahead and build a simple provider and consumer Web Part that you can connect. The provider Web Part will enable users to enter a ZIP code. The consumer Web Part displays the weather for the selected ZIP code (see Figure 27.15).
First, you need to create an interface which describes the information being passed between the provider and consumer Web Parts. Our interface is contained in Listing 27.22.
The IZIPCode
interface defines one read-only property named ZIPCode
. This is the bit of information that will pass between the two Web Parts.
The IZIPCode
interface must be saved in the App_Code folder or it will not be automatically compiled.
Next, you need to create the provider Web Part. This Web Part enables a user to enter a ZIP code in a text box. The ZIPCodePart
is contained in Listing 27.23.
Example 27.23. ZIPCodePart.ascx
<%@ Control Language="VB" ClassName="ZIPCodePart" %> <%@ Implements Interface="IZIPCode" %> <script runat="server"> ''' <summary> ''' Implements the IZIPCode interface ''' </summary> Public ReadOnly Property ZIPCode() As String Implements IZIPCode.ZIPCode Get Return txtZIPCode.Text End Get End Property ''' <summary> ''' This method is called from connected Web Parts ''' </summary> <ConnectionProvider("ZIP Code")> _ Public Function ProvideZIPCode() As IZIPCode Return Me End Function </script> <asp:Label id="lblZIPCode" AssociatedControlID="txtZIPCode" Text="ZIP Code:" Runat="server" /> <asp:TextBox id="txtZIPCode" Runat="server" /> <asp:Button id="btnSubmit" Text="Submit" Runat="server" />
Notice that the ZIPCodePart
includes a method named ProvideZIPCode()
, which is decorated with the ConnectionProvider
attribute. This method is called by any consumer Web Parts connected to the ZIPCodePart
.
The ProvideZIPCode()
method returns the ZIPCodePart
itself when the method is called. Notice that the ZIPCodePart
implements the IZIPCode
interface. The Web Part includes an <%@ Implements %>
directive and it implements the ZIPCode
property.
The provider Web Part is not required to implement the interface it exposes. If you prefer, you could return a different class that implements the IZIPCode
interface from the ProvideZIPCode()
method.
Now you are ready to create the consumer Web Part. This Web Part, named WeatherPart
, displays the current weather. The code for the WeatherPart
is contained in Listing 27.24.
Example 27.24. WeatherPart.ascx
<%@ Control Language="VB" ClassName="WeatherPart" %> <script runat="server"> Private _zipCode As IZIPCode ''' <summary> ''' This method retrieves the IZIPCode interface returned ''' by the ProvideZIPCode method ''' </summary> <ConnectionConsumer("ZIP Code")> _ Public Sub ConsumeZIPCode(ByVal zipCode As IZIPCode) _zipCode = zipCode End Sub ''' <summary> ''' Display the weather ''' </summary> Private Sub Page_PreRender() ' Check if we are connected If Not _zipCode Is Nothing Then If _zipCode.ZIPCode <> String.Empty Then lblWeather.Text = String.Format("The weather for {0} is expected to be sunny!", _zipCode.ZIPCode) Else lblWeather.Text = "Please enter your ZIP code" End If End If End Sub </script> <h3>Current Weather</h3> <asp:Label id="lblWeather" Runat="server" />
The WeatherPart
contains a method named ConsumeZIPCode()
that is decorated with the ConnectionConsumer
attribute. This method is called when a class that implements the IZIPCode
interface is returned from the provider Web Part.
The ConsumeZIPCode()
method assigns the class that implements the IZIPCode
interface to a private field. The private field is used to display the weather in the Page_PreRender()
method.
When working with connected Web Parts, it is important to know when in the page execution lifecycle the consumer Web Part actually calls the provider Web Part. This happens during the Page’s LoadComplete
event, which occurs right after the Page’s Load event.
For this reason, the information exposed by a provider Web Part is not available during a consumer Web Part’s Load
event. You should place all your logic that depends on this information in the Web Part’s PreRender
event handler.
Finally, you can create a Web Part page that hosts the ZIPCodePart
and WeatherPart
. This page is contained in Listing 27.25.
Example 27.25. ConnectedSimpleParts.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="ZIPCodePart" Src="~/ZIPCodePart.ascx" %> <%@ Register TagPrefix="user" TagName="WeatherPart" Src="~/WeatherPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:40%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Connected Simple Parts</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server"> <StaticConnections> <asp:WebPartConnection ID="WebPartConnection1" ProviderID="ZIPCodePart1" ConsumerID="WeatherPart1" /> </StaticConnections> </asp:WebPartManager> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:ZIPCodePart id="ZIPCodePart1" Title="ZIP Code Part" Description="Enables entry of ZIP code" Runat="Server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server"> <ZoneTemplate> <user:WeatherPart id="WeatherPart1" Title="Weather Part" Description="Displays current weather" Runat="Server" /> </ZoneTemplate> </asp:WebPartZone> </form> </body> </html>
The page in Listing 27.25 contains the ZIPCodePart
and WeatherPart
in its two Web Part Zones. The two Web Parts are statically connected by the WebPartManager
control. Notice that the WebPartManager
control includes a <StaticConnections>
section that connects the two parts.
After you open the page in Listing 27.25 in your web browser, you can enter a ZIP code in the ZIPCodePart
and see the ZIP code displayed in the WeatherPart
.
This section tackles a slightly more complicated sample of connected Web Parts. You connect two Web Parts that display database data.
The provider Web Part displays a list of movie categories, and the consumer Web Part displays a list of movies. When the Web Parts are connected, you can select a movie category and see a list of matching movies (see Figure 27.16).
The first thing to do is define the interface that describes the information passed from the provider Web Part to the consumer Web Part. The interface is contained in Listing 27.26.
The next step is to create the provider Web Part that exposes the IMovieCategory
interface. The MovieCategoryPart
is contained in Listing 27.27. This Web Part enables you to select a movie from a drop-down list.
Example 27.27. MovieCategoryPart.ascx
<%@ Control Language="VB" ClassName="MovieCategoryPart" %> <%@ Implements Interface="IMovieCategory" %> <script runat="server"> ''' <summary> ''' Implements IMovieCategoryPart.SelectedCategoryId ''' </summary> Public ReadOnly Property SelectedCategoryId() As Integer Implements IMovieCategory.SelectedCategoryId Get Return CInt(dropCategories.SelectedValue) End Get End Property ''' <summary> ''' This method is called from connected Web Parts ''' </summary> <ConnectionProvider("Movie Category")> _ Public Function ProvideCategory() As IMovieCategory Return Me End Function </script> <asp:Label id="lblCategory" Text="Movie Category:" AssociatedControlID="dropCategories" Runat="server" /> <asp:DropDownList id="dropCategories" DataSourceId="srcCategories" DataTextField="Name" DataValueField="Id" AutoPostBack="true" Runat="server" /> <asp:Button id="btnSelect" Text="Select" Runat="server" /> <asp:SqlDataSource id="srcCategories" ConnectionString="Server=.SQLExpress; Integrated Security=True;AttachDbFileName=|DataDirectory|MyDatabase.mdf; User Instance=True" SelectCommand="SELECT Id,Name FROM MovieCategories" Runat="server" />
The MovieCategoryPart
contains a DropDownList
control bound to a SqlDataSource
control. The SqlDataSource
control represents the contents of a SQL Express database table named MovieCategories
.
Notice that the Web Part includes a method named ProvideCategory()
, which is decorated with the ConnectionProvider
attribute. This method returns a reference to the MovieCategoryPart
when a consumer Web Part connects to the MovieCategoryPart
.
The next step is to create the consumer Web Part. The consumer Web Part is named MovieListPart
and it is contained in Listing 27.28.
Example 27.28. MovieListPart.ascx
<%@ Control Language="VB" ClassName="MovieListPart" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <script runat="server"> Private _category As IMovieCategory ''' <summary> ''' This method is called when the ProvideCategory method ''' returns a class that implements the IMovieCategory interface ''' </summary> <ConnectionConsumer("Movie Category")> _ Public Sub ConsumeCategory(ByVal category As IMovieCategory) _category = category End Sub ''' <summary> ''' Update SelectedCategoryId from Provider Web Part ''' </summary> Private Sub Page_PreRender() If Not _category Is Nothing Then srcMovies.SelectParameters("CategoryId").DefaultValue = _category.SelectedCategoryId.ToString() End If End Sub </script> <asp:GridView id="grdMovies" DataSourceId="srcMovies" Runat="server" /> <asp:SqlDataSource id="srcMovies" ConnectionString="Server=.SQLExpress;Integrated Security=True; AttachDbFileName=|DataDirectory|MyDatabase.mdf;User Instance=True" SelectCommand="SELECT Title,Director,YearReleased FROM Movies WHERE CategoryId=@CategoryId" Runat="server"> <SelectParameters> <asp:Parameter Name="CategoryId" Type="int32" /> </SelectParameters> </asp:SqlDataSource>
The MovieListPart
displays a list of movies in a GridView
control. When you connect the MovieListPart
to the MovieCategoryPart
, the MovieListPart
displays only those movies that match the selected movie category.
Notice that the MovieListPart
includes a method named ConsumeCategory()
, which is decorated with the ConnectionConsumer
attribute. This method retrieves the class that implements the IMovieCategory
interface (the MovieCategoryPart
) from the provider Web Part.
The Page_PreRender()
method updates the list of movies displayed in the GridView
control. The method updates the value of the CategoryId
parameter used by the SqlDataSource
control.
Finally, you can create a page that hosts the provider and consumer Web Parts. The page is contained in Listing 27.29.
Example 27.29. ConnectedDataParts.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="MovieCategoryPart" Src="~/MovieCategoryPart.ascx" %> <%@ Register TagPrefix="user" TagName="MovieListPart" Src="~/MovieListPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:45%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Connected Data Parts</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server"> <StaticConnections> <asp:WebPartConnection ID="WebPartConnection1" ProviderID="MovieCategoryPart1" ConsumerID="MovieListPart1" /> </StaticConnections> </asp:WebPartManager> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:MovieCategoryPart id="MovieCategoryPart1" Title="Movie Category Part" Description="Displays movie categories" Runat="Server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server"> <ZoneTemplate> <user:MovieListPart id="MovieListPart1" Title="Movie List Part" Description="Displays list of movies" Runat="Server" /> </ZoneTemplate> </asp:WebPartZone> </form> </body> </html>
The page in Listing 27.29 statically connects the MovieCategoryPart
and MovieListPart
Web Parts. The static connection is created in the WebPartManager
control’s <StaticConnections>
section.
In the previous sections, you connected Web Parts by declaring a static connection between the Web Parts. Creating a static connection makes sense when the Web Parts themselves are also statically declared in the page.
There are situations, however, in which you will want to enable users of your application to form dynamic connections between Web Parts. For example, you might want to allow a user to add a new Web Part to a page from a catalog of Web Parts and connect the new Web Part to an existing Web Part.
You can enable users to create dynamic connections between Web Parts by adding a Connections Zone to a page. The page in Listing 27.30 illustrates how you can declare a Connections Zone.
Example 27.30. ConnectedDynamicParts.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="ZIPCodePart" Src="~/ZIPCodePart.ascx" %> <%@ Register TagPrefix="user" TagName="WeatherPart" Src="~/WeatherPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Connected Dynamic Parts</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server" /> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> <asp:MenuItem Text="Connect" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server" /> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server" /> <asp:CatalogZone id="CatalogZone1" CssClass="column" Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart id="DeclarativeCatalogPart1" Runat="server"> <WebPartsTemplate> <user:ZIPCodePart id="ZIPCodePart1" Title="ZIP Code Part" Description="Enables entry of ZIP code" Runat="Server" /> <user:WeatherPart id="WeatherPart1" Title="Weather Part" Description="Displays current weather" Runat="Server" /> </WebPartsTemplate> </asp:DeclarativeCatalogPart> </ZoneTemplate> </asp:CatalogZone> <asp:ConnectionsZone id="ConnectionsZone" CssClass="column" Runat="server" /> </form> </body> </html>
Notice that, unlike other tool zones, the Connections Zone does not include any parts. In Listing 27.30, a <ConnectionsZone>
tag is declared in the page without any child elements.
If you open the page in Listing 27.30 in your browser, you can click the Catalog link to display the contents of the Declarative Catalog. Next, you can add an instance of both the ZIPCodePart
and WeatherPart
to the page. At this point, the two Web Parts are not connected.
Next, you can connect the Web Parts by clicking the Connect link and selecting Connect from either of the two Web Part control’s menus. For example, if you select Connect from the WeatherPart
control’s menu and click the Create a Connection to a Provider link, the connection interface in Figure 27.17 appears.
You can select the ZIP Code Part from the drop-down list to connect the two Web Parts. After the Web Parts are connected, entering a ZIP code causes the Weather Part to display the weather for that ZIP code.
For two Web Parts to communicate, the two Web Parts must agree on a common interface. With careful planning, a single developer can build a set of Web Parts and interfaces that enable all the Web Parts contained in an application to communicate cleanly.
However, imagine that you need to connect Web Parts created by different developers in your organization. Or imagine that you need to connect Web Parts sold by different companies. It is unlikely that the Web Parts will share exactly the same interfaces.
In situations in which you do not have control over the interface exposed by a Web Part, you can take advantage of a Transformer to modify the interface. A Transformer enables you to transform the data passed between a provider Web Part and a consumer Web Part.
Imagine, for example, that you buy a new Web Part—named the LocalNewsPart
—that displays a list of local news headlines. You want to use this new Web Part with your existing ZIPCodePart
and WeatherPart
in an application.
Unfortunately, you quickly discover that you cannot connect the LocalNewsPart
to the ZIPCodePart
control. The two Web Parts expect different interfaces. To solve this problem, you need to create a Transformer.
The LocalNewsPart
Web Part is contained in Listing 27.31.
Example 27.31. LocalNewsPart.ascx
<%@ Control Language="VB" ClassName="LocalNewsPart" %> <script runat="server"> Private _zipCode As INewsZIPCode ''' <summary> ''' This method retrieves the INewsZIPCode interface returned ''' by the provider Web Part ''' </summary> <ConnectionConsumer("News ZIP Code")> _ Public Sub ConsumeZIPCode(ByVal zipCode As INewsZIPCode) _zipCode = zipCode End Sub ''' <summary> ''' Display the news ''' </summary> Private Sub Page_PreRender() ' Check if we are connected If Not _zipCode Is Nothing Then If _zipCode.ZIPCode <> String.Empty Then lblNews.Text = String.Format("Everything looks terrific for {0}!", _zipCode.ZIPCode) Else lblNews.Text = "Please enter your ZIP code" End If End If End Sub </script> <h3>Current News</h3> <asp:Label id="lblNews" Runat="server" />
The LocalNewsPart
Web Part uses the interface defined in Listing 27.32—the INewsZIPCode
interface—to represent a ZIP code.
The INewsZIPCode
interface represents a ZIP code in exactly the same way as the IZIPCode
interface used by the ZIPCodePart
and WeatherPart
Web Parts. Unfortunately, however, it is a different interface. Therefore, before you can connect the LocalNewsPart
Web Part to the ZIPCodePart
, you must first define a Transformer.
The Transformer in Listing 27.33 converts an instance of the IZIPCode
interface to an instance of the INewsZIPCode
interface.
Example 27.33. App_CodeIPCodeTransformer.vb
Imports System Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' This class transforms an IZIPCode to ''' an INewsZIPCode ''' </summary> <WebPartTransformer(GetType(IZIPCode), GetType(INewsZIPCode))> _ Public Class ZIPCodeTransformer Inherits WebPartTransformer Public Overrides Function Transform(ByVal providerData As Object) As Object Return New TempZIP((CType(providerData, IZIPCode)).ZIPCode) End Function End Class Public Class TempZIP Implements INewsZIPCode Private _zipCode As String Public ReadOnly Property ZIPCode() As String Implements INewsZIPCode.ZIPCode Get Return _zipCode End Get End Property Friend Sub New(ByVal zipCode As String) _zipCode = zipCode End Sub End Class End Namespace
After you create the file in Listing 27.33, you need to add it to your application’s App_Code
folder to automatically compile the Transformer class.
There are a number of things that you should notice about the code for the Transformer. First, notice that the ZIPCodeTransformer
class is decorated with a WebPartTransformer
attribute. This attribute has two parameters: the provider interface and the consumer interface.
Next, you should notice that the ZIPCodeTransformer
class derives from the base WebPartTransformer
class. The ZIPCodeTransformer
class overrides the base class’s Transform()
method. The Transform()
method takes the instance of the interface provided by the provider Web Part and transforms it into an instance of an interface appropriate for the consumer Web Part.
The WebPartTransformer
class includes another useful method that you can override: the CreateConfigurationControl()
method. You can use this method to return an editor for configuring a Transformer. The Transformer editor appears when you click the Edit button in the Connections Zone.
Before you can use a Transformer in an application, you must register the Transformer in your application’s web configuration file. The file in Listing 27.34 contains the necessary configuration settings.
After you are finished setting up the Transformer, you can use the Transformer when creating either a static or dynamic connection between Web Parts. The page in Listing 27.35 demonstrates how you can declare a Transformer when creating a static connection between the ZIPCodePart
and the LocalNewsPart
Web Parts.
Example 27.35. ConnectedTransformerParts.aspx
<%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="ZIPCodePart" Src="~/ZIPCodePart.ascx" %> <%@ Register TagPrefix="user" TagName="WeatherPart" Src="~/WeatherPart.ascx" %> <%@ Register TagPrefix="user" TagName="LocalNewsPart" Src="~/LocalNewsPart.ascx" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <style type="text/css"> .column { float:left; width:45%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Connected Transformer Parts</title> </head> <body> <form id="form1" runat="server"> <asp:WebPartManager id="WebPartManager1" Runat="server"> <StaticConnections> <asp:WebPartConnection ID="WebPartConnection1" ProviderID="ZIPCodePart1" ConsumerID="WeatherPart1" /> <asp:WebPartConnection ID="WebPartConnection2" ProviderID="ZIPCodePart1" ConsumerID="LocalNewsPart1"> <custom:ZIPCodeTransformer Runat="Server" /> </asp:WebPartConnection> </StaticConnections> </asp:WebPartManager> <asp:Menu id="Menu1" OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" CssClass="menu" Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> </Items> </asp:Menu> <asp:WebPartZone id="WebPartZone1" CssClass="column" Runat="server"> <ZoneTemplate> <user:ZIPCodePart id="ZIPCodePart1" Title="ZIP Code Part" Description="Enables entry of ZIP code" Runat="Server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone id="WebPartZone2" CssClass="column" Runat="server"> <ZoneTemplate> <user:WeatherPart id="WeatherPart1" Title="Weather Part" Description="Displays current weather" Runat="Server" /> <user:LocalNewsPart id="LocalNewsPart1" Title="Local News Part" Description="Displays current news" Runat="Server" /> </ZoneTemplate> </asp:WebPartZone> </form> </body> </html>
The ZIPCodeTransformer
is registered at the top of the page in Listing 27.35. The page uses the ZIPCodeTransformer
in the declaration of the static connection between the ZIPCodePart
and the LocalNewsPart
Web Parts.
After you configure a Transformer in an application’s web configuration file, you don’t need to do anything special to use the Transformer in a page in which you are dynamically connecting Web Parts.
For example, the page in Listing 27.35 contains a catalog that lists the ZIPCodePart
, the WeatherPart
, and the LocalNewsPart
. You can add all three Web Parts to a page and then connect the Web Parts by clicking the Connect link and selecting the Connect menu option included in each Web Part menu. If you connect the LocalNewsPart
to the ZIPCodePart
, the connection will automatically use the ZIPCodeTransformer
.
This chapter introduced you to the Web Part Framework. You learned how to use each of the different types of zones that you can add to a Web Part page.
You learned how to use Web Part Zones to mark the areas in a page that can contain Web Parts. You also saw how you can take advantage of Catalog Zones to enable users to add new Web Parts to a page at runtime. You learned how to use Editor Zones to enable users to edit Web Part properties. Finally, you learned how to use Connections Zones to enable users to create dynamic connections between Web Parts.