Chapter 28. Building Web Parts

<feature><title>In this Chapter</title> <objective>

Creating Simple Web Parts

</objective>
<objective>

Filtering Web Parts

</objective>
<objective>

Creating Custom Web Part Verbs

</objective>
<objective>

Displaying Web Part Help

</objective>
<objective>

Managing Web Parts with the WebPartManager Control

</objective>
<objective>

Summary

</objective>
</feature>

This chapter is devoted exclusively to the topic of building Web Parts. You learn how to create Web Parts by creating User controls and by creating custom controls that derive from the base WebPart class.

We also examine the important topic of authorization filters. You learn how to display different sets of Web Parts to different users. For example, you learn how to create Web Parts that only members of the Administrator role can view.

Later in this chapter, custom Web Part verbs are discussed. You learn how to add custom menu items to a Web Part and execute server-side and client-side code when a user selects the menu item.

This chapter also explores how you can add help to Web Parts. You learn how to open a modal dialog box that displays a help page.

Warning

For many of the samples to work in this chapter, you must enable authentication for your application. Windows authentication is enabled by default. For more information about authentication, see Chapter 20, “Using the Login Controls.”

Finally, the WebPartManager class is examined. You learn how to take advantage of this class to programmatically manipulate the Web Parts contained in a page.

Creating Simple Web Parts

Technically, there are two types of Web Parts. You can create a Web Part by adding any ASP.NET control—including any custom control or User control—to a Web Part Zone. Alternatively, you can create a Web Part by building a custom control that derives from the base WebPart class.

The Web Part Framework handles these two types of Web Parts differently. When you add a standard ASP.NET control to a Web Part Zone, the Web Part Framework wraps the control in a GenericWebPart control. Wrapping a standard control in a GenericWebPart adds all the standard Web Part properties to the control.

For example, if you add an Image control to a Web Part Zone, the Web Part Framework automatically creates a new GenericWebPart control that includes the Image control as its only child control.

If, on the other hand, you create a Web Part by building a custom control that derives from the base WebPart class, the Web Part Framework doesn’t need to do anything special with the control. The control is already a Web Part.

Because the GenericWebPart class itself derives from the base WebPart class, you can do anything with a generic Web Part that you can do with a “True” Web Part with one important limitation. Because a control gets wrapped in a GenericWebPart at runtime, there are a number of Web Part properties that you cannot set declaratively when working with a generic Web Part.

In this section, you learn how to create simple Web Parts. You also learn how to take advantage of both the core and extended properties supported by Web Part controls.

The Hello World Web Part

All authors of programming books are contractually obligated to include at least one Hello World sample in every book that they write. In this section, two Hello World Web Parts illustrate how to create a Web Part with a User control and a custom control derived from the base WebPart class. In other words, both a Generic Web Part and a True Web Part are created.

The Generic Hello World Web Part is contained in Listing 28.1.

Example 28.1. HelloWorldPart.ascx

<%@ Control Language="VB" ClassName="HelloWorldPart" %>

Hello World!

Notice how simple the Generic Hello World Web Part is. The control simply renders a single line of text.

Creating a True Web Part that does the same thing isn’t that much more difficult. The Web Part in Listing 28.2 inherits from the base WebPart class, making it a True Web Part.

Example 28.2. App_CodeHelloWorldPart.vb

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

Namespace myControls

    ''' <summary>
    ''' True Web Part
    ''' </summary>
    Public Class HelloWorldPart
        Inherits WebPart

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            writer.Write("Hello World!")
        End Sub

    End Class
End Namespace

The class in Listing 28.2 inherits from the base WebPart class and overrides the RenderContents() method to display the single line of text.

Note

You must add the file in Listing 28.2 to the App_Code folder for the control to be automatically compiled.

The page in Listing 28.3 displays both the Generic and True Web Parts.

Example 28.3. ShowHelloWorldPart.aspx

<%@ Page Language="VB" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<%@ Register TagPrefix="user" TagName="HelloWorldPart" Src="~/HelloWorldPart.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:45%;
            height:200px;
            margin-right:10px;
            border:solid 1px black;
            background-color: white;
        }
        html
        {
            background-color:#eeeeee;
        }
    </style>
    <title>Show Hello World Part</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        Runat="server" />
        <asp:WebPartZone
            id="WebPartZone1"
            CssClass="column"
            Runat="server">
            <ZoneTemplate>
            <user:HelloWorldPart
                id="HelloWorldPart1"
                Runat="server" />
            </ZoneTemplate>
        </asp:WebPartZone>

        <asp:WebPartZone
            id="WebPartZone2"
            CssClass="column"
            Runat="server">
            <ZoneTemplate>
            <custom:HelloWorldPart
                id="HelloWorldPart2"
                Runat="server" />
            </ZoneTemplate>
        </asp:WebPartZone>

    </form>
</body>
</html>

After you open the page in Listing 28.3, you’ll see two Web Part Zones. The Generic Hello World Web Part is contained in the first zone and the True Web Part is contained in the second zone (see Figure 28.1).

The Hello World Web Parts.

Figure 28.1. The Hello World Web Parts.

Notice that both Web Parts are registered at the top of the page. As an alternative to registering Web Parts in each page, you can register the Web Parts once in an application’s web configuration file, as is shown in Listing 28.4.

Example 28.4. Web.Config

<?xml version="1.0"?>
<configuration>
    <system.web>
    <pages>
      <controls>
        <add tagPrefix="custom" namespace="myControls" />
        <add tagPrefix="user" tagName="HelloWorldPart"
                src="~/WebParts/HelloWorldPart.ascx"/>
      </controls>
    </pages>
    </system.web>
</configuration>

When you register a User control in the web configuration file, you must place the User control in a different folder than any page that uses it (otherwise, you’ll get an exception). Typically, you should locate all your user controls in a subfolder in your application. In the web configuration file in Listing 28.4, the HelloWorldPart.ascx file has been moved to a folder named WebParts.

Standard Web Part Properties

As mentioned earlier, both Generic and True Web Parts support a core set of properties:

  • AuthorizationFilter—. Enables you to specify a string that the Web Part Manager can check before adding a Web Part to a page.

  • CatalogIconImageUrl—. Enables you to specify the icon displayed for the Web Part when the Web Part is listed in a Catalog Part.

  • Description—. Enables you to specify the description displayed for the Web Part as a tooltip when you hover your mouse over the Web Part.

  • ExportMode—. Enables you to export a Web Part control’s settings to an XML file. Possible values are All, None, and NonSensitiveData.

  • Height—. Enables you to specify the height of a Web Part control.

  • Subtitle—. Enables you to add an additional string to the end of the title displayed in a Web Part.

  • Title—. Enables you to specify the title of the Web Part displayed, for example, in the title bar.

  • TitleIconImageUrl—. The title icon image is displayed next to the title in the title bar.

  • TitleUrl—. Enables you to convert the title into a hyperlink that links to a page with more information about the Web Part.

  • Width—. Enables you to specify the width of the Web Part.

You can set any of these properties declaratively on any control that you add to a Web Part Zone. For example, you can set the Title and Description properties like this:

<user:HelloWorldPart
  id="HelloWorldPart1"
  Title="Hello World"
  Description="Displays Hello World"
  Runat="server" />

Visual Web Developer Note

When working in Source view in Visual Web Developer, you get a green squiggle warning when setting Web Part properties such as the Title or Description property for a User control. Technically, you are setting expando properties because the UserControl class doesn’t know anything about the specialized Web Part properties. You can safely ignore the warning messages.

Alternatively, you can supply any of these properties with default values in the Web Part control itself. You set these properties in different ways depending on whether you are working with a Generic Web Part control or a True Web Part control.

When setting default Web Part property values for a Generic Web Part control, you need to implement the IWebPart interface. For example, Listing 28.5 contains the code for a Random Quote Web Part.

Example 28.5. RandomQuotePart.ascx

<%@ Control Language="VB" ClassName="RandomQuotePart" %>
<%@ Implements Interface="System.Web.UI.WebControls.WebParts.IWebPart" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script runat="server">

    Private _title As String = "Random Quote"
    Private _titleUrl As String = "~/Help.aspx"
    Private _description As String = "Displays a random quote"
    Private _subTitle As String = "User Control Version"
    Private _catalogIconImageUrl As String = "~/Images/BigRandomQuote.gif"
    Private _titleIconImageUrl As String = "~/Images/SmallRandomQuote.gif"

    Public Property Title() As String Implements IWebPart.Title
        Get
            Return _title
        End Get
        Set(ByVal Value As String)
            _title = Value
        End Set
    End Property

    Public Property TitleUrl() As String Implements IWebPart.TitleUrl
        Get
            Return _titleUrl
        End Get
        Set(ByVal Value As String)
            _titleUrl = Value
        End Set
    End Property
    Public Property Description() As String Implements IWebPart.Description
        Get
            Return _description
        End Get
        Set(ByVal Value As String)
            _description = Value
        End Set
    End Property

    Public ReadOnly Property Subtitle() As String Implements IWebPart.Subtitle
        Get
            Return _subTitle
        End Get
    End Property

    Public Property CatalogIconImageUrl() As String Implements IWebPart.CatalogIconImageUrl
        Get
            Return _catalogIconImageUrl
        End Get
        Set(ByVal Value As String)
            _catalogIconImageUrl = Value
        End Set
    End Property

    Public Property TitleIconImageUrl() As String Implements IWebPart.TitleIconImageUrl
        Get
            Return _titleIconImageUrl
        End Get
        Set(ByVal Value As String)
            _titleIconImageUrl = Value
        End Set
    End Property

    Private Sub Page_PreRender()
        Dim quotes As New List(Of String)
        quotes.Add("All paid jobs absorb and degrade the mind -- Aristotle")
        quotes.Add("No evil can happen to a good man, either in life or after death -- Plato")
        quotes.Add("The only good is knowledge and the only evil is ignorance -- Plato")
        Dim rnd As New Random()
        lblQuote.Text = quotes(rnd.Next(quotes.Count))
    End Sub
</script>

<asp:Label
    id="lblQuote"
    runat="server" />

Notice that the User control in Listing 28.5 implements the IWebPart interface. It includes an <%@ Implements %> directive at the top of the file. Default values are provided for each of the standard Web Part properties.

When working with a True Web Part control, you do not need to implement the IWebPart interface. Because a True Web Part control derives from the base WebPart class, and the WebPart class contains all the properties of the IWebPart interface, you simply need to override the Web Part properties that you want to modify.

The Web Part in Listing 28.6 also displays a random quotation. However, this control is a True Web Part control.

Example 28.6. App_CodeRandomQuotePart.vb

Imports System
Imports System.Collections.Generic
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

Namespace myControls

    ''' <summary>
    ''' Displays a random quotation
    ''' </summary>
    Public Class RandomQuotePart
        Inherits WebPart

        Private _title As String = "Random Quote"
        Private _titleUrl As String = "~/Help.aspx"
        Private _description As String = "Displays a random quote"
        Private _subTitle As String = "True Web Part Version"
        Private _catalogIconImageUrl As String = "~/Images/BigRandomQuote.gif"
        Private _titleIconImageUrl As String = "~/Images/SmallRandomQuote.gif"

        Public Overrides Property Title() As String
            Get
                Return _title
            End Get
            Set(ByVal Value As String)
                _title = value
            End Set
        End Property

        Public Overrides Property TitleUrl() As String
            Get
                Return _titleUrl
            End Get
            Set(ByVal Value As String)
                _titleUrl = value
            End Set
        End Property

        Public Overrides Property Description() As String
            Get
                Return _description
            End Get
            Set(ByVal Value As String)
                _description = value
            End Set
        End Property

        Public Overrides ReadOnly Property Subtitle() As String
            Get
                Return _subTitle
            End Get
        End Property

        Public Overrides Property CatalogIconImageUrl() As String
            Get
                Return _catalogIconImageUrl
            End Get
            Set(ByVal Value As String)
                _catalogIconImageUrl = value
            End Set
        End Property

        Public Overrides Property TitleIconImageUrl() As String
            Get
                Return _titleIconImageUrl
            End Get
            Set(ByVal Value As String)
               _titleIconImageUrl = value
            End Set
        End Property

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            Dim quotes As New List(Of String)()
            quotes.Add("All paid jobs absorb and degrade the mind -- Aristotle")
            quotes.Add("No evil can happen to a good man, either in life or after death -- Plato")
            quotes.Add("The only good is knowledge and the only evil is ignorance -- Plato")
            Dim rnd As New Random()
            writer.Write(quotes(rnd.Next(quotes.Count)))
        End Sub

    End Class
End Namespace

Notice that the class in Listing 28.6 overrides the properties of the base WebPart class. For example, the RandomQuotePart class overrides the Title property of the base WebPart class to display a default title for the Web Part (see Figure 28.2).

Displaying random quotations.

Figure 28.2. Displaying random quotations.

CD Note

You can view the RandomQuotePart with the ShowRandomQuotePart.aspx page included on the CD which accompanies this book.

Creating a User Control Web Part Base Class

Implementing the IWebPart interface in a User Control every time you want to supply a default value for a Web Part property quickly gets tedious. Because the IWebPart interface is an interface, you are obligated to implement all the properties included in the interface even if you need to supply a value for only one of the properties.

To make your life easier, you can create a custom base class for every Web Part that you create with a User control. The UserControlWebPartBase class in Listing 28.7 creates default values for all the core Web Part properties.

Example 28.7. App_CodeUserControlWebPartBase.vb

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

''' <summary>
''' Base Class for User Control Web Parts
''' </summary>
Public Class UserControlWebPartBase
    Inherits UserControl
    Implements IWebPart

    Private _title As String = "Untitled"
    Private _titleUrl As String = String.Empty
    Private _description As String = String.Empty
    Private _subTitle As String = String.Empty
    Private _catalogIconImageUrl As String = String.Empty
    Private _titleIconImageUrl As String = String.Empty

    Public Property Title() As String Implements IWebPart.Title
        Get
            Return _title
        End Get
        Set(ByVal Value As String)
            _title = Value
        End Set
    End Property

    Public Property TitleUrl() As String Implements IWebPart.TitleUrl
        Get
            Return _titleUrl
        End Get
        Set(ByVal Value As String)
            _titleUrl = Value
        End Set
    End Property

    Public Property Description() As String Implements IWebPart.Description
        Get
            Return _description
        End Get
        Set(ByVal Value As String)
            _description = Value
        End Set
    End Property

    Public ReadOnly Property Subtitle() As String Implements IWebPart.Subtitle
        Get
            Return _subTitle
        End Get
    End Property

    Public Property CatalogIconImageUrl() As String Implements IWebPart.CatalogIconImageUrl
        Get
            Return _catalogIconImageUrl
        End Get
        Set(ByVal Value As String)
            _catalogIconImageUrl = Value
        End Set
    End Property

    Public Property TitleIconImageUrl() As String Implements IWebPart.TitleIconImageUrl
        Get
            Return _titleIconImageUrl
        End Get
        Set(ByVal Value As String)
            _titleIconImageUrl = Value
        End Set
    End Property

End Class

After you create the class in Listing 28.7, you can derive all your User Control Web Parts from this class. For example, the MinimalPart Web Part in Listing 28.8 inherits from the UserControlWebPartBase class.

Example 28.8. MinimalPart.ascx

<%@ Control Language="VB" ClassName="MinimalPart"
  Inherits="UserControlWebPartBase" %>

<script runat="server">

    Sub Page_Load()
        Me.Title = "Minimal Part"
        Me.Description = "Displays hardly anything at all"
    End Sub

</script>

Minimal

The <%@ Control %> directive includes an Inherits attribute that causes the User Control to inherit from the base UserControlWebPartBase class. Notice that you are not obligated to implement all the properties of the IWebPart interface in the MinimalPart. Only the Title and Description properties are set.

CD Note

You can view the MinimalPart with the ShowMinimalPart.aspx page included on the CD that accompanies this book.

Using Extended Web Part Properties

True Web Parts are slightly more powerful than Generic Web Parts. Not all Web Part properties are exposed through the IWebPart interface.

When deriving a Web Part from the base WebPart class, you can take advantage of any of the following properties:

  • AllowClose—. Enables you to prevent users from closing a Web Part.

  • AllowConnect—. Enables you to prevent users from connecting a Web Part.

  • AllowEdit—. Enables you to prevent users from editing a Web Part.

  • AllowHide—. Enables you to prevent users from hiding a Web Part.

  • AllowMinimize—. Enables you to prevent users from minimizing (collapsing) a Web Part.

  • AllowZoneChange—. Enables you to prevent users from moving a Web Part.

  • AuthorizationFilter—. Enables you to specify a string that the Web Part Manager can check before adding a Web Part to a page.

  • CatalogIconImageUrl—. Enables you to specify the icon displayed for the Web Part when the Web Part is listed in a Catalog Part.

  • ChromeState—. Enables you to get or set whether a Web Part is currently minimized or maximized. Possible values are Minimized and Normal.

  • ChromeType—. Enables you to get or set the appearance of a Web Part’s chrome. Possible values are BorderOnly, Default, None, TitleAndBorder, and TitleOnly.

  • ConnectErrorMessage—. Enables you to get the error message displayed when errors happen while Web Parts are connected.

  • CreateEditorParts—. Enables you to associate particular Editor Parts with a Web Part.

  • Description—. Enables you to specify the description displayed for the Web Part as a tooltip when you hover your mouse over the Web Part.

  • ExportMode—. Enables you to specify whether a Web Part’s settings can be exported to an XML file.

  • HasSharedData—. Enables you to determine whether a Web Part has Shared Personalization data.

  • HasUserData—. Enables you to determine whether a Web Part has User Personalization data.

  • Height—. Enables you to specify the height of a Web Part control.

  • HelpMode—. Enables you to specify the type of user interface displayed for help. Possible values are Modal, Modeless, and Navigate.

  • HelpUrl—. Enables you to get or set the URL for a help page associated with the Web Part.

  • Hidden—. Enables you to get or set whether a Web Part is hidden. When a Web Part is hidden, the Web Part is rendered with the Cascading Style Sheet attribute display:none.

  • ImportErrorMessage—. Enables you to get or set the message displayed when an error occurs during the import process.

  • IsClosed—. Enables you to determine whether a Web Part is closed.

  • IsShared—. Enables you to determine whether a Web Part is visible to all users of a Web Part page.

  • IsStandalone—. Enables you to determine whether a Web Part is visible to only certain users of a Web Part page.

  • IsStatic—. Enables you to determine whether a Web Part is declared in a Web Part Zone (as opposed to being added from a Catalog Zone).

  • Subtitle—. Enables you to add an additional string to the end of the title displayed in a Web Part.

  • Title—. Enables you to specify the title of the Web Part displayed, for example, in the title bar.

  • TitleIconImageUrl—. The title icon image is displayed next to the title in the title bar.

  • TitleUrl—. Enables you to convert the title into a hyperlink that links to a page with more information about the Web Part.

  • WebBrowsableObject—. Enables you to retrieve the object that is edited by an Editor Part.

  • WebPartManager—. Enables you to get the WebPartManager control responsible for tracking a Web Part.

  • Width—. Enables you to specify the width of the Web Part.

  • Verbs—. Enables you to retrieve the collection of menu items displayed by a Web Part.

  • Zone—. Enables you to get the zone that contains a Web Part.

  • ZoneIndex—. Enables you to get the position of a Web Part in a zone.

You can override any of these properties when building a True Web Part control. For example, Listing 28.9 contains a Web Part named the IrritatingPart. The IrritatingPart control is hidden and cannot be closed or minimized.

Example 28.9. App_CodeIrritatingPart.vb

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

Namespace myControls

    ''' <summary>
    ''' Hidden Part that cannot be closed
    ''' or minimized.
    ''' </summary>
    Public Class IrritatingPart
        Inherits WebPart
        Private _title As String = "Irritating Part"
        Private _description As String = "This Web Part is irritating"
        Private _hidden As Boolean = True
        Private _allowClose As Boolean = False
        Private _allowMinimize As Boolean = False

        Public Overrides Property Title() As String
            Get
                Return _title
            End Get
            Set(ByVal Value As String)
                _title = Value
            End Set
        End Property

        Public Overrides Property Description() As String
            Get
                Return _description
            End Get
            Set(ByVal Value As String)
                _description = Value
            End Set
        End Property

        Public Overrides Property Hidden() As Boolean
            Get
                Return _hidden
            End Get
            Set(ByVal Value As Boolean)
                _hidden = Value
            End Set
        End Property

        Public Overrides Property AllowClose() As Boolean
            Get
                Return _allowClose
            End Get
            Set(ByVal Value As Boolean)
                _allowClose = Value
            End Set
        End Property

        Public Overrides Property AllowMinimize() As Boolean
            Get
                Return _allowMinimize
            End Get
            Set(ByVal Value As Boolean)
                _allowMinimize = False
            End Set
        End Property

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            writer.Write("<h1>You can't get rid of me!</h1>")
        End Sub

    End Class

End Namespace

If you add the Web Part in Listing 28.9 to a page, then you won’t be able to see the Web Part in Browse Display mode because the Web Part overrides the Hidden property to hide itself. You can only see the IrritatingPart when a page is in Design or Catalog Display mode. You also cannot close or minimize the Web Part because both these properties are also overridden (see Figure 28.3).

An Irritating Web Part.

Figure 28.3. An Irritating Web Part.

CD Note

You can view the IrritatingPart with the ShowIrritatingPart.aspx page included on the CD that accompanies this book.

Note

Of course, the IrritatingPart Web Part is not a very realistic sample of when you would use the Hidden property. When a Web Part is hidden, the Web Part is rendered but not visible. The Cascading Style Sheet display:none property is set. Using the Hidden property is useful when you want to add a non-visual Web Part to a page such as a data source Web Part that exposes all the records from the Movies database table. The Hidden Web Part can be connected to Web Parts that aren’t hidden.

You cannot set any of the properties discussed in this section declaratively in the case of a Generic Web Part. Because the controls in a Web Part Zone do not get wrapped in the GenericWebPart class until runtime, a Generic Web Part is not a Web Part until a page is actually executed.

However, you can set any of these properties programmatically in the case of either a Generic or True Web Part. The GenericWebPart class derives from the base WebPart class, so you can do anything with a Generic Web Part that you can do with a True Web Part. The only requirement is that you do it programmatically rather than declaratively.

For example, the page in Listing 28.10 contains three links for minimizing the Web Parts contained in the page (see Figure 28.4).

Minimizing Web Parts.

Figure 28.4. Minimizing Web Parts.

Example 28.10. MinimizeWebParts.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">

    ''' <summary>
    ''' Minimize All Web Parts
    ''' </summary>
    Protected Sub lnkMinimizeAll_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim part As WebPart
        For Each part In WebPartManager1.WebParts
            part.ChromeState = PartChromeState.Minimized
        Next
    End Sub

    ''' <summary>
    ''' Minimize Zone 1 Web Parts
    ''' </summary>
    Protected Sub lnkMinimizeZone1_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim part As WebPart
        For Each part In WebPartZone1.WebParts
            part.ChromeState = PartChromeState.Minimized
        Next
    End Sub

    ''' <summary>
    ''' Minimize Zone 2 Web Parts
    ''' </summary>
    Protected Sub lnkMinimizeZone2_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim part As WebPart
        For Each part In WebPartZone2.WebParts
            part.ChromeState = PartChromeState.Minimized
        Next
    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;
        }
        html
        {
            background-color:#eeeeee;
        }
    </style>
    <title>Minimize Web Parts</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        Runat="server" />

    <asp:LinkButton
        id="lnkMinimizeAll"
        Text="Minimize All"
        Runat="server" OnClick="lnkMinimizeAll_Click" />

    <div class="column">
    <asp:LinkButton
        id="lnkMinimizeZone1"
        Text="Minimize"
        OnClick="lnkMinimizeZone1_Click"
        Runat="server" />
    <asp:WebPartZone
        id="WebPartZone1"
        Runat="server">
        <ZoneTemplate>
        <asp:Label
            id="Label1"
            Title="First Part"
            Text="First Part"
            Runat="server" />
        <asp:Label
            id="Label2"
            Title="Second Part"
            Text="Second Part"
            Runat="server" />
        </ZoneTemplate>
    </asp:WebPartZone>
    </div>

    <div class="column">
    <asp:LinkButton
        id="lnkMinimizeZone2"
        Text="Minimize"
        OnClick="lnkMinimizeZone2_Click"
        Runat="server" />
    <asp:WebPartZone
        id="WebPartZone2"
        Runat="server">
        <ZoneTemplate>
        <asp:Label
            id="Label3"
            Title="Third Part"
            Text="Third Part"
            Runat="server" />
        <asp:Label
            id="Label4"
            Title="Fourth Part"
            Text="Fourth Part"
            Runat="server" />
        </ZoneTemplate>
    </asp:WebPartZone>
    </div>

    </form>
</body>
</html>

When you click the Minimize All link, the collection of all the Web Parts in the page is retrieved from the WebPartManager control, and the ChromeState property for each Web Part is set to the value Minimized. If you click the Minimize link associated with a particular zone, then the Web Parts are retrieved from the Zone’s WebParts property and the Web Parts in the selected zone are minimized.

Notice that the ChromeState property can be set, even for the Generic Web Parts (Labels) in the page. Because the Generic Web Parts are being retrieved from the WebPartManager and WebPartZone WebParts collection, the controls in the Web Part Zones have already been wrapped in the GenericWebPart class that includes all the properties of a True Web Part.

By taking advantage of the WebParts property exposed by both the WebPartManager and WebPartZone controls, you can retrieve information about the Web Parts contained in a page. For example, the User control in Listing 28.11—the WebPartInfo control—displays several properties of the Web Parts contained in the page.

Example 28.11. WebPartInfo.ascx

<%@ Control Language="VB" ClassName="WebPartInfo" %>
<script runat="server">

    Sub Page_PreRender()
        Dim wpm As WebPartManager = WebPartManager.GetCurrentWebPartManager(Page)
        grdInfo.DataSource = wpm.WebParts
        grdInfo.DataBind()
    End Sub

</script>

<asp:GridView
    id="grdInfo"
    AutoGenerateColumns="false"
    Runat="server">
    <Columns>
    <asp:BoundField HeaderText="Title" DataField="Title" />
    <asp:BoundField HeaderText="IsShared" DataField="IsShared" />
    <asp:BoundField HeaderText="IsStatic" DataField="IsStatic" />
    <asp:BoundField HeaderText="IsClosed" DataField="IsClosed" />
    <asp:BoundField HeaderText="HasUserData" DataField="HasUserData" />
    <asp:BoundField HeaderText="HasSharedData" DataField="HasSharedData" />
    </Columns>
</asp:GridView>

You can add the User Control in Listing 28.11 to any page to view the properties of the Web Parts in the page (see Figure 28.5).

Displaying Information about Web Parts.

Figure 28.5. Displaying Information about Web Parts.

CD Note

You can view the information displayed by the WebPartInfo control by opening the ShowWebPartInfo.aspx page located on the CD that accompanies this book.

Filtering Web Parts

When building a Web Part application, you might want to allow different users of the application to see different sets of Web Parts. For example, you might want the president of the company to be able to view the World Domination Plans Web Part, but you wouldn’t want a lowly temporary employee to see the contents of this particular Web Part. On the other hand, you might want everyone in the company to be able to see the Copying Machine Locations Web Part.

You can filter the Web Parts that a user can see on a Web Part page. When you create an authorization filter, only the Web Parts that a person is authorized to view will appear in Web Part Zones and Web Part Catalogs.

You can create an authorization filter in either of two ways. First, you can handle the AuthorizeWebPart event of the WebPartManager control class. This event is raised every time that a Web Part is added to the page while the Web Part Framework builds the page. The event argument passed to the event handler for the AuthorizeWebPart event includes an IsAuthorized property. You can set this property to the value True or False to indicate whether a Web Part is authorized to be displayed.

You can also create an authorization filter by creating a custom WebPartManager control that inherits from the WebPartManager control and overrides its IsAuthorized() method. The IsAuthorized() method returns a Boolean value. If you return the value False, then a Web Part fails authorization and it is not added to the page. Using this second way of creating an authorization filter makes sense when you want to apply the same authorization logic to multiple Web Part pages in an application.

Regardless of whether you handle the AuthorizeWebPart event or you override the IsAuthorized() method, it is up to you to write the logic for the authorization filter. In the following sections, you’ll learn three ways of filtering Web Parts, depending on the role of the user.

Filtering by Authorization Filter

One of the core properties shared by every Web Part is the AuthorizationFilter property. This property represents a string that you can use when filtering Web Parts. You can assign any string value to this property.

For example, you can use the AuthorizationFilter property to represent a user role. In that case, in your AuthorizeWebPart event handler, you can prevent users who are not in the correct role from seeing a Web Part.

In this section, we create three Web Parts: the MissionStatementPart, the CopyingMachinesLocationPart, and the WorldDominationPlanPart. These Web Parts are contained in Listings 28.12, 13, and 14.

Example 28.12. MissionStatementPart.ascx

<%@ Control Language="VB" ClassName="MissionStatementPart" %>

<h3>Mission Statement</h3>
The purpose of this company is...

Example 28.13. CopyingMachinesLocationPart.ascx

<%@ Control Language="VB" ClassName="CopyingMachinesLocationPart" %>

<h3>Copying Machines Location</h3>
The copying machines are located on the 5th floor...

Example 28.14. WorldDominationPlansPart.ascx

<%@ Control Language="VB" ClassName="WorldDominationPlansPart" %>

<h3>World Domination Plans</h3>
Start by placing secret messages in every Unleashed book...

Notice that there is nothing special about these Web Parts. They are simply User controls.

Next, because the Web Parts are filtered by user role, roles need to be enabled for the application. One option would be to use Windows Authentication and local Windows groups. This is the default type of authentication enabled for an ASP.NET application and there is nothing wrong with this option. However, this sample uses Forms Authentication and custom roles. It is easier to switch between users when using Forms Authentication, which makes it easier to test the page.

Forms Authentication and custom roles can be enabled with the Web configuration file in Listing 28.15.

Example 28.15. Web.Config

<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <system.web>
      <authentication mode="Forms" />
      <roleManager enabled="true" />
      <membership defaultProvider="MyMembershipProvider">
      <providers>
      <add name="MyMembershipProvider"
        type="System.Web.Security.SqlMembershipProvider"
        connectionStringName="LocalSqlServer"
        requiresQuestionAndAnswer="false"
        minRequiredNonalphanumericCharacters="0"
        minRequiredPasswordLength="1"
        requiresUniqueEmail="false" />
      </providers>
      </membership>
    </system.web>
</configuration>

CD Note

The configuration file in Listing 28.15 is included on the CD with the name Web.Config_Disabled so that the configuration file doesn’t interfere with the other samples in this chapter.

The web configuration file in Listing 28.15 enables Forms Authentication and the Role Manager. It also configures the Membership provider so that email addresses and strong passwords are not required when creating a new user. (This makes it easier to create new users in the page.)

Finally, the page in Listing 28.16 uses an authorization filter to display the three Web Parts (see Figure 28.6).

Filtering Web Parts.

Figure 28.6. Filtering Web Parts.

Example 28.16. ShowAuthorizationFilter.aspx

<%@ Page Language="VB" %>
<%@ Register TagPrefix="user" TagName="MissionStatementPart"
  Src="~/MissionStatementPart.ascx" %>
<%@ Register TagPrefix="user" TagName="WorldDominationPlansPart"
  Src="~/WorldDominationPlansPart.ascx" %>
<%@ Register TagPrefix="user" TagName="CopyingMachineLocationsPart"
  Src="~/CopyingMachinesLocationPart.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<script runat="server">

    ''' <summary>
    ''' Create the Administrator and Serf roles and
    ''' create two users named Bill and Tom.
    ''' </summary>
    Private  Sub Page_Load()
        If Not Roles.RoleExists("Administrator") Then
            Roles.CreateRole("Administrator")
            Roles.CreateRole("Serf")
            Membership.CreateUser("Bill", "secret")
            Membership.CreateUser("Tom", "secret")
            Roles.AddUserToRoles("Bill", New String(){"Administrator", "Serf"})
            Roles.AddUserToRole("Tom", "Serf")
        End If
    End Sub

    ''' <summary>
    ''' Only add a Web Part when the AuthorizationFilter
    ''' property contains the current user's role or the
    ''' AuthorizationFilter property is empty.
    ''' </summary>
    Protected Sub WebPartManager1_AuthorizeWebPart(ByVal sender As Object, ByVal e As WebPartAuthorizationEventArgs)
        e.IsAuthorized = User.IsInRole(e.AuthorizationFilter) Or e.AuthorizationFilter = String.Empty
    End Sub

    ''' <summary>
    ''' Hide the menu for unauthorized users
    ''' </summary>
    Private  Sub Page_PreRender()
        Menu1.Visible = Request.IsAuthenticated
    End Sub

    Protected  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">
        .login
        {
            border:solid 1px black;
            background-color:white;
        }
        .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 Authorization Filter</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart"
        Runat="server" />

    <asp:Login
        id="Login1"
        CssClass="login"
        TitleText=""
        Orientation="horizontal"
        DisplayRememberMe="false"
        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:MissionStatementPart
            id="MissionStatementPart1"
            title="Mission Statement"
            runat="server" />
        <user:CopyingMachineLocationsPart
            id="CopyingMachineLocationsPart1"
            title="Copying Machine Locations"
            AuthorizationFilter="Serf"
            runat="server" />
        <user:WorldDominationPlansPart
            id="WorldDominationPart1"
            title="World Domination Plans"
            AuthorizationFilter="Administrator"
            runat="server" />
        </ZoneTemplate>
    </asp:WebPartZone>

    <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:CopyingMachineLocationsPart
                id="CopyingMachineLocationsPart1"
                title="Copying Machine Locations"
                AuthorizationFilter="Serf"
                runat="server" />
            <user:WorldDominationPlansPart
                id="WorldDominationPart1"
                title="World Domination Plans"
                AuthorizationFilter="Administrator"
                runat="server" />
            </WebPartsTemplate>
        </asp:DeclarativeCatalogPart>
        <asp:PageCatalogPart
            id="PageCatalogPart1"
            Runat="server" />
        </ZoneTemplate>
    </asp:CatalogZone>

    </form>
</body>
</html>

The Page_Load() method in Listing 28.16 automatically creates two roles named Administrator and Serf. The method also creates two users named Bill and Tom. Bill is associated with both the Administrator and Serf role and Tom is associated with the Serf role.

After you open the page in Listing 28.16, you’ll see only the MissionStatementPart Web Part because this is the only Web Part that anonymous users can view.

If you log in with the username Tom and password secret, then you can see both the MissionStatementPart and CopyingMachineLocationsPart Web Parts. Both these Web Parts are visible in both the Web Part Zone and Catalog Zone contained in the page.

Finally, if you log in with the username Bill and the password secret, you can see all three Web Parts. All three Web Parts are displayed in both the Web Part Zone and the Catalog Zone.

Notice that the CopyingMachinesLocationPart and WorldDominationPlansPart Web Parts are declared with an AuthorizationFilter attribute. The CopyingMachinesLocationPart is associated with the Serf user role. The WorldDominiationPlansPart is associated with the Administrator user role.

The WebPartManager control has an AuthorizeWebPart event handler associated with it. The event handler consists of the following line of code:

e.IsAuthorized = User.IsInRole(e.AuthorizationFilter) Or e.AuthorizationFilter = String.Empty

This line of code checks whether the current user is a member of the role represented by a Web Part’s AuthorizationFilter property. If the user is in the role associated with the Web Part or the Web Part has no role associated with it, then the user is authorized to see the Web Part.

Filtering by User Control Path

Using the AuthorizationFilter property is potentially dangerous when you use the property with Generic Web Parts. The problem is that you might forget to add the AuthorizationFilter attribute when adding a Generic Web Part to a zone. Because the AuthorizationFilter property is not a member of the IWebPart interface, you cannot set this property in the User Control itself.

This section explores an alternate method of creating an authorization filter. This method works only with Web Parts created as User Controls. Web Parts will be filtered depending on their paths.

The idea is that to place every Web Part that a member of the Administrator role can see in a folder named Administrator. Furthermore, every Web Part that a member of the Serf role can see will be located in a folder named Serf.

Let’s start by creating the two User Controls contained in Listing 28.17 and 18.

Example 28.17. SerfSerfPart.ascx

<%@ Control Language="VB" ClassName="SerfPart" %>

<h3>Serf Part</h3>

Example 28.18. AdministratorAdministratorPart.ascx

<%@ Control Language="VB" ClassName="AdministratorPart" %>

<h3>Administrator Part</h3>

The SerfPart Web Part is located in the Serf folder and the AdministratorPart Web Part is located in the Administrator folder.

The page in Listing 28.19 filters the two Web Parts. Different Web Parts are displayed, depending on the role of the current user.

Example 28.19. ShowAuthorizationPath.aspx

<%@ Page Language="VB" %>
<%@ Register TagPrefix="user" TagName="AdministratorPart"
 Src="~/Administrator/AdministratorPart.ascx" %>
<%@ Register TagPrefix="user" TagName="SerfPart" Src="~/Serf/SerfPart.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    ''' <summary>
    ''' Create the Administrator and Serf roles and
    ''' the Bill and Tom user accounts
    ''' </summary>
    Private  Sub Page_Load()
        If Not Roles.RoleExists("Administrator") Then
            Roles.CreateRole("Administrator")
            Roles.CreateRole("Serf")
            Membership.CreateUser("Bill", "secret")
            Membership.CreateUser("Tom", "secret")
            Roles.AddUserToRoles("Bill", New String(){"Administrator", "Serf"})
            Roles.AddUserToRole("Tom", "Serf")
        End If
    End Sub

    ''' <summary>
    ''' Filter based on the Web Part User Control path
    ''' </summary>
    Protected  Sub WebPartManager1_AuthorizeWebPart(ByVal sender As Object, ByVal e As WebPartAuthorizationEventArgs)
        e.IsAuthorized = User.IsInRole(GetFolder(e.Path))
    End Sub

    ''' <summary>
    ''' Gets the name of the folder that contains
    ''' the User Control
    ''' </summary>
    Private Function GetFolder(ByVal path As String) As String
        Dim baseFolder As String = String.Empty
        Dim parts As String() = path.Split("/"c)
        If parts.Length > 2 Then
            baseFolder = parts(1)
        End If
        Return baseFolder
    End Function

    Private  Sub Page_PreRender()
        Menu1.Visible = Request.IsAuthenticated
    End Sub

    Protected  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">
        .login
        {
            border:solid 1px black;
            background-color:white;
        }
        .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 Authorization Path</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart"
        Runat="server" />

    <asp:Login
        id="Login1"
        CssClass="login"
        TitleText=""
        Orientation="horizontal"
        DisplayRememberMe="false"
        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:AdministratorPart
            id="AdministratorPart1"
            title="Administrator Part"
            runat="server" />
        <user:SerfPart
            id="SerfPart1"
            title="Serf Part"
            runat="server" />
        </ZoneTemplate>
    </asp:WebPartZone>

    <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:AdministratorPart
            id="AdministratorPart1"
            title="Administrator Part"
            runat="server" />
        <user:SerfPart
            id="SerfPart1"
            title="Serf Part"
            runat="server" />
            </WebPartsTemplate>
        </asp:DeclarativeCatalogPart>
        <asp:PageCatalogPart
            id="PageCatalogPart1"
            Runat="server" />
        </ZoneTemplate>
    </asp:CatalogZone>

    </form>
</body>
</html>

After you open the page in Listing 28.19, you won’t see any Web Parts. If you log in with the username Tom and password secret, you’ll see the SerfPart Web Part. If you log in with the user name Bill and password secret, you’ll see both the SerfPart and AdministratorPart Web Part (Bill is a member of both the Administrator and Serf roles).

The AuthorizeWebPart event handler consists of the following single line of code:

e.IsAuthorized = User.IsInRole( GetFolder(e.Path) )

The GetFolder() method returns the root folder of the Web Part being authorized. In other words, it returns the name of the folder where the User Control that corresponds to the Web Part is located. If the name of the root folder matches one of the current user’s roles, then the Web Part is authorized and it is displayed in the page.

Filtering by Custom Control Type

You can’t filter a True Web Part by its path because a True Web Part doesn’t have a path. However, you can do something similar. Rather than filter a True Web Part by its path, you can filter a True Web Part by its type.

In this section, two Web Part base classes are created, named AdministratorWebPartBase and SerfWebPartBase. Anyone who is a member of the Administrator role can see any Web Part that inherits directly from the AdministratorWebPartBase class, and anyone who is a member of the Serf role can see any Web Part that inherits directly from the SerfWebPartBase class.

The AdministratorWebPartBase and SerfWebPartBase classes are contained in Listing 28.20 and Listing 28.21.

Example 28.20. App_CodeAdministratorWebPartBase.cs

Imports System
Imports System.Web.UI.WebControls.WebParts

Namespace myControls

    ''' <summary>
    ''' Base class for all Web Parts that
    ''' an Administrator is authorized to see
    ''' </summary>
    Public MustInherit Class AdministratorWebPartBase
        Inherits WebPart
    End Class
End Namespace

Example 28.21. App_CodeSerfWebPartBase.cs

Imports System
Imports System.Web.UI.WebControls.WebParts

Namespace myControls

    ''' <summary>
    ''' Base class for all Web Parts that
    ''' a member of the Serf role is authorized
    ''' to see.
    ''' </summary>
    Public MustInherit Class SerfWebPartBase
        Inherits WebPart
    End Class
End Namespace

Now that we have the base classes, we can inherit any number of Administrator and Serf Web Parts from the base classes. Listing 28.22 and Listing 28.23 contain an Administrator Web Part and a Serf Web Part.

Example 28.22. App_CodeAdministratorPart.cs

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts
Namespace myControls
    ''' <summary>
    ''' A Web Part that only an Administrator can see
    ''' </summary>
    Public Class AdministratorPart
        Inherits AdministratorWebPartBase
        Private _title As String = "Administrator Part"

        Public Overrides Property Title() As String
            Get
                Return _title
            End Get
            Set(ByVal Value As String)
                _title = value
            End Set
        End Property

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            writer.RenderBeginTag(HtmlTextWriterTag.H3)
            writer.Write("Administrator Part")
            writer.RenderEndTag()
        End Sub
    End Class
End Namespace

Example 28.23. App_CodeSerfPart.cs

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

Namespace myControls
    ''' <summary>
    ''' A Web Part that only a Serf can see
    ''' </summary>
    Public Class SerfPart
        Inherits SerfWebPartBase
        Private _title As String = "Serf Part"

        Public Overrides Property Title() As String
            Get
                Return _title
            End Get
            Set(ByVal Value As String)
                _title = value
            End Set
        End Property

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            writer.RenderBeginTag(HtmlTextWriterTag.H3)
            writer.Write("Serf Part")
            writer.RenderEndTag()
        End Sub
    End Class
End Namespace

Notice that the AdministratorPart inherits from the AdministratorWebPartBase class, and the SerfPart inherits from the SerfWebPartBase class. The authorization filter in Listing 28.24 takes advantage of that fact.

Example 28.24. ShowAuthorizationType.aspx

<%@ Page Language="VB" %>
<%@ 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">

    ''' <summary>
    ''' Create the Administrator and Serf roles and
    ''' the Bill and Tom user accounts.
    ''' </summary>
    Private  Sub Page_Load()
        If Not Roles.RoleExists("Administrator") Then
            Roles.CreateRole("Administrator")
            Roles.CreateRole("Serf")
            Membership.CreateUser("Bill", "secret")
            Membership.CreateUser("Tom", "secret")
            Roles.AddUserToRoles("Bill", New String(){"Administrator", "Serf"})
            Roles.AddUserToRole("Tom", "Serf")
        End If
    End Sub

    ''' <summary>
    ''' Authorizes a user to see a Web Part when the base type of the Web Part
    ''' matches one of the user's roles
    ''' </summary>
    Protected  Sub WebPartManager1_AuthorizeWebPart(ByVal sender As Object, ByVal e As WebPartAuthorizationEventArgs)
        e.IsAuthorized = User.IsInRole(GetRoleFromType(e.Type))
    End Sub

    ''' <summary>
    ''' Returns the name of the base class from a type
    ''' after stripping the text WebPartBase
    ''' </summary>
    Private Function GetRoleFromType(ByVal partType As Type) As String
        Dim typeName As String = partType.BaseType.Name
        Return typeName.Replace("WebPartBase", String.Empty)
    End Function

    Private  Sub Page_PreRender()
        Menu1.Visible = Request.IsAuthenticated
    End Sub

    Protected  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">
        .login
        {
            border:solid 1px black;
            background-color:white;
        }
        .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 Authorization Type</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart"
        Runat="server" />

    <asp:Login
        id="Login1"
        CssClass="login"
        TitleText=""
        Orientation="horizontal"
        DisplayRememberMe="false"
        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>
        <custom:AdministratorPart
            id="AdministratorPart1"
            runat="Server" />
        <custom:SerfPart
            id="SerfPart1"
            runat="server" />
        </ZoneTemplate>
    </asp:WebPartZone>

    <asp:WebPartZone
        id="WebPartZone2"
        CssClass="column"
        Runat="server" />

    <asp:CatalogZone
        id="CatalogZone1"
        CssClass="column"
        Runat="server">
        <ZoneTemplate>
        <asp:DeclarativeCatalogPart
            id="DeclarativeCatalogPart"
            Runat="server">
            <WebPartsTemplate>
            <custom:AdministratorPart
                id="AdministratorPart1"
                runat="Server" />
            <custom:SerfPart
                id="SerfPart1"
                runat="server" />
            </WebPartsTemplate>
        </asp:DeclarativeCatalogPart>
        </ZoneTemplate>
    </asp:CatalogZone>

    </form>
</body>
</html>

Once again, Tom only can see the SerfPart Web Part, and Bill can see both the SerfPart and AdministratorPart Web Parts. The AuthorizeWebPart event handler consists of the following single line of code:

e.IsAuthorized = User.IsInRole(GetRoleFromType(e.Type))

The GetRoleFromType() method returns the name of the base type of the current Web Part (and strips the string "WebPartBase" from the name). If the current user is a member of the role represented by the base type, then the user can see the Web Part.

Creating Custom Web Part Verbs

In the terminology of the Web Part Framework, a menu item displayed by a Web Part is called a verb. In this section, you’ll learn how to extend the standard set of verbs displayed by a Web Part with your own custom verbs. You’ll learn how to create verbs that execute both server-side and client-side code. You’ll also learn how to add verbs to every Web Part that appears in a particular Web Part Zone.

Creating Server-Side Verbs

Adding new verbs to a Web Part is easy. You simply need to provide the Web Part with a Verbs property that returns the collection of verbs that you want the Web Part to display.

Listing 28.25 contains a Generic Web Part that contains a custom Add to Cart verb.

Example 28.25. ProductPart.ascx

<%@ Control Language="VB" ClassName="ProductPart" %>
<%@ Implements Interface="System.Web.UI.WebControls.WebParts.IWebActionable" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script runat="server">

    Private _productName As String
    Private _productPrice As Decimal

    Public ReadOnly Property Verbs() As WebPartVerbCollection Implements IWebActionable.Verbs
        Get
            Dim menu As New List(Of WebPartVerb)
            Dim menuItem As New WebPartVerb("AddToCart", AddressOf AddToCart)
            menuItem.Text = "Add To Cart"
            menuItem.Description = "Adds item to shopping cart"
            menuItem.ImageUrl = "~/Images/AddToCart.gif"
            menu.Add(menuItem)
            Return New WebPartVerbCollection(menu)
        End Get
    End Property

    Public  Sub AddToCart(ByVal s As Object, ByVal e As WebPartEventArgs)
        Dim wpm As WebPartManager =  WebPartManager.GetCurrentWebPartManager(Page)
        wpm.MoveWebPart(e.WebPart, wpm.Zones("ShoppingCartZone"), 0)
    End Sub
    Public Property ProductName() As String
    Get
         Return _productName
    End Get
    Set (ByVal Value As String)
        productName = value
    End Set
    End Property

    Public Property ProductPrice() As Decimal
    Get
      Return _productPrice
    End Get
    Set (ByVal Value As Decimal)
      productPrice = value
    End Set
    End Property

</script>

<h3><%= _productName %></h3>
Price: <%= _productPrice.ToString("c") %>

Notice that the Web Part in Listing 28.25 implements the IWebActionable interface. It includes an <%@ Implements %> directive at the top of the file. This interface contains one member: the Verbs property.

The Verbs property returns the verbs (menu items) displayed by the Web Part. In the case of the ProductPart Web Part, a new verb is created, which displays the text Add to Cart. The verb also displays an image and it is associated with a server-side method named AddToCart().

The AddToCart() method moves the current Web Part into a Web Part Zone named the ShoppingCartZone. When you select the Add to Cart menu option on the ProductPart, the Web Part is moved to the Shopping Cart Zone.

Listing 28.26 contains the same ProductPart implemented as a True Web part.

Example 28.26. App_CodeProductPart.vb

Imports System
Imports System.Collections.Generic
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

Namespace myControls
    Public Class ProductPart
        Inherits WebPart
        Private _title As String = "Product Part"
        Private _productName As String
        Private _productPrice As Decimal

        Public Overrides Property Title() As String
            Get
                Return _title
            End Get
            Set(ByVal Value As String)
                _title = value
            End Set
        End Property

        Public Overrides ReadOnly Property Verbs() As WebPartVerbCollection
            Get
                Dim menu As New List(Of WebPartVerb)()
                Dim menuItem As New WebPartVerb("AddToCart", AddressOf AddToCart)
                menuItem.Text = "Add To Cart"
                menuItem.Description = "Adds item to shopping cart"
                menuItem.ImageUrl = "~/Images/AddToCart.gif"
                menu.Add(menuItem)
                Return New WebPartVerbCollection(menu)
            End Get
        End Property

        Public Sub AddToCart(ByVal s As Object, ByVal e As WebPartEventArgs)
            Dim wpm As WebPartManager = WebPartManager.GetCurrentWebPartManager(Page)
            wpm.MoveWebPart(e.WebPart, wpm.Zones("ShoppingCartZone"), 0)
        End Sub

        Public Property ProductName() As String
            Get
                Return _productName
            End Get
            Set(ByVal Value As String)
                _productName = value
            End Set
        End Property

        Public Property ProductPrice() As Decimal
            Get
                Return _productPrice
            End Get
            Set(ByVal Value As Decimal)
                _productPrice = value
            End Set
        End Property

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            writer.RenderBeginTag(HtmlTextWriterTag.H3)
            writer.Write(_productName)
            writer.RenderEndTag()
            writer.Write("Price: {0:c}", _productPrice)
        End Sub

    End Class
End Namespace

Notice that the class in Listing 28.26 does not implement the IWebActionable interface. It doesn’t need to implement this interface because the base WebPart class already includes a Verbs property.

You can view both versions of the ProductPart with the page in Listing 28.27 (see Figure 28.7).

Displaying custom menu items.

Figure 28.7. Displaying custom menu items.

Example 28.27. ShowProductPart.aspx

<%@ Page Language="VB" %>
<%@ Register TagPrefix="user" TagName="ProductPart" Src="~/ProductPart.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">

    Protected  Sub lnkClear_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim part As WebPart
        For Each part In ShoppingCartZone.WebParts
            WebPartManager1.MoveWebPart(part, ProductZone, 0)
        Next
    End Sub

    Private  Sub Page_PreRender()
        lnkClear.Visible = (ShoppingCartZone.WebParts.Count > 0)
    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%;
            padding:10px;
            height:200px;
            margin-right:10px;
            border:solid 1px black;
            background-color: white;
        }
        html
        {
            background-color:#eeeeee;
        }
    </style>
    <title>Show Product Part</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        Runat="server" />

        <div class="column">
        <h1>Products</h1>
        <asp:WebPartZone
            id="ProductZone"
            HeaderText="Products"
            MenuPopupStyle-BackColor="aliceBlue"
            MenuPopupStyle-BorderStyle="solid"
            MenuPopupStyle-BorderWidth="1px"
            MenuPopupStyle-BorderColor="black"
            MenuPopupStyle-ShadowColor="lightgray"
            AllowLayoutChange="false"
            Runat="server">
            <ZoneTemplate>
            <user:ProductPart
                id="ProductPart1"
                Title="Product"
                ProductName="Laptop Computer"
                ProductPrice="876.23"
                Runat="server"/>
            <custom:ProductPart
                id="ProductPart2"
                ProductName="Computer Monitor"
                ProductPrice="500.89"
                Runat="server"/>
            </ZoneTemplate>
        </asp:WebPartZone>
        </div>

        <div class="column">
        <h1>Shopping Cart</h1>
        <asp:WebPartZone
            id="ShoppingCartZone"
            HeaderText="Shopping Cart"
            VerbStyle-CssClass="verbs"
            AllowLayoutChange="false"
            Runat="server"/>
        <asp:LinkButton
            id="lnkClear"
            Text="Clear Cart"
            OnClick="lnkClear_Click"
            runat="server" />
        </div>
    </form>
</body>
</html>

After you open the page in Listing 28.27, you can select the Add to Cart menu option from either of the two Web Parts to add the Web Part to the Shopping Cart Zone. Notice that the page also contains a Clear Cart link. Clicking this link moves all the Web Parts back from the Shopping Cart Zone to the Web Part Zone.

Creating Client-Side Verbs

A Web Part verb can execute client-side code as well as server-side code. The client-side code can do anything you want. For example, you can call any JavaScript function that you have defined in your page.

In this section, the ProductPart Web Part is modified so that it displays a confirmation dialog box before adding a Web Part to the Shopping Cart Zone. The modified ProductPart, named ConfirmProductPart, is contained in Listing 28.28.

Example 28.28. ConfirmProductPart.ascx

<%@ Control Language="VB" ClassName="ConfirmProductPart" %>
<%@ Implements Interface="System.Web.UI.WebControls.WebParts.IWebActionable" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script runat="server">
    Private _productName As String
    Private _productPrice As Decimal

    Public ReadOnly Property Verbs() As WebPartVerbCollection Implements IWebActionable.Verbs
    Get
            Dim menu As New List(Of WebPartVerb)()
            Dim menuItem As New WebPartVerb("AddToCart", AddressOf AddToCart, "return confirm('Are You Sure?'),")
            menuItem.Text = "Add To Cart"
            menuItem.Description = "Adds item to shopping cart"
            menuItem.ImageUrl = "~/Images/AddToCart.gif"
            menu.Add(menuItem)
            Return New WebPartVerbCollection(menu)
        End Get
    End Property
    Public  Sub AddToCart(ByVal s As Object, ByVal e As WebPartEventArgs)
        Dim wpm As WebPartManager =  WebPartManager.GetCurrentWebPartManager(Page)
        wpm.MoveWebPart(e.WebPart, wpm.Zones("ShoppingCartZone"), 0)
    End Sub

    Public Property ProductName() As String
        Get
                 Return _productName
        End Get
        Set (ByVal Value As String)
                 _productName = value
        End Set
    End Property

    Public Property ProductPrice() As Decimal
        Get
                 Return _productPrice
        End Get
        Set (ByVal Value As Decimal)
                 _productPrice = value
        End Set
    End Property

</script>

<h3><%= _productName %></h3>
Price: <%= _productPrice.ToString("c") %>

The ConfirmProductPart is identical to the ProductPart that was created in the previous section, except for the one line of code that is highlighted in bold in Listing 28.28. A little bit of JavaScript code has been added, which opens a confirmation dialog box whenever someone selects the Add to Cart menu option (see Figure 28.8).

Displaying a Confirmation dialog box.

Figure 28.8. Displaying a Confirmation dialog box.

CD Note

You can view the ConfirmProductPart by opening the ShowConfirmProductPart.aspx page included on the CD that accompanies this book.

If your JavaScript code returns the value false, then the server-side code has not executed. Therefore, if you click the Cancel button in the JavaScript confirmation dialog box, the server-side AddToCart() method is not executed.

Creating Zone Verbs

One problem with the ProductPart Web Part is that it displays the Add to Cart menu item no matter in what zone the Web Part is displayed. In particular, the Web Part displays this menu option even when the Web Part is already located in the Shopping Cart Zone.

There is a way to fix this problem. Rather than create a custom verb at the level of an individual Web Part, you can create a custom verb at the level of a Web Part Zone. When you create a zone verb, every Web Part contained in the zone gets the additional verb automatically.

The page in Listing 28.29 handles the CreateVerbs event associated with the Product Zone to add a verb to every Web Part in the zone.

Example 28.29. ShowZoneVerbs.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    ''' <summary>
    ''' Create the verbs that will appear for every
    ''' Web Part in the Product Zone
    ''' </summary>
    Protected Sub ProductZone_CreateVerbs(ByVal sender As Object, ByVal e As WebPartVerbsEventArgs)
        Dim menu As New List(Of WebPartVerb)()
        Dim menuItem As New WebPartVerb("AddToCart", AddressOf AddToCart, "return confirm('Are You Sure?'),")
        menuItem.Text = "Add To Cart"
        menuItem.Description = "Adds item to shopping cart"
        menuItem.ImageUrl = "~/Images/AddToCart.gif"
        menu.Add(menuItem)
        e.Verbs = New WebPartVerbCollection(e.Verbs, menu)
    End Sub

    ''' <summary>
    ''' Move a Web Part from the Product Zone
    ''' to the Shopping Cart Zone
    ''' </summary>
    Public  Sub AddToCart(ByVal s As Object, ByVal e As WebPartEventArgs)
        Dim wpm As WebPartManager =  WebPartManager.GetCurrentWebPartManager(Page)
        wpm.MoveWebPart(e.WebPart, wpm.Zones("ShoppingCartZone"), 0)
    End Sub

    Protected  Sub lnkClear_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim part As WebPart
        For Each part In ShoppingCartZone.WebParts
            WebPartManager1.MoveWebPart(part, ProductZone, 0)
        Next
    End Sub

    Private  Sub Page_PreRender()
        lnkClear.Visible = (ShoppingCartZone.WebParts.Count > 0)
    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%;
            padding:10px;
            height:200px;
            margin-right:10px;
            border:solid 1px black;
            background-color: white;
        }
        html
        {
            background-color:#eeeeee;
        }
    </style>
    <title>Show Zone Verbs</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        Runat="server" />

        <div class="column">
        <h1>Products</h1>
        <asp:WebPartZone
            id="ProductZone"
            OnCreateVerbs="ProductZone_CreateVerbs"
            HeaderText="Products"
            MenuPopupStyle-BackColor="aliceBlue"
            MenuPopupStyle-BorderStyle="solid"
            MenuPopupStyle-BorderWidth="1px"
            MenuPopupStyle-BorderColor="black"
            MenuPopupStyle-ShadowColor="lightgray"
            AllowLayoutChange="false"
            Runat="server">
            <ZoneTemplate>
            <asp:Label
                id="Label1"
                Title="Product"
                Text="Laptop Computer -- $900.00"
                Runat="server" />
            <asp:Label
                id="Label2"
                Title="Product"
                Text="Computer Monitor -- $900.00"
                Runat="server" />
            <asp:Label
                id="Label3"
                Title="Product"
                Text="Network Card -- $64.20"
                Runat="server" />
            </ZoneTemplate>
        </asp:WebPartZone>
        </div>

        <div class="column">
        <h1>Shopping Cart</h1>
        <asp:WebPartZone
            id="ShoppingCartZone"
            HeaderText="Shopping Cart"
            VerbStyle-CssClass="verbs"
            AllowLayoutChange="false"
            Runat="server"/>
        <asp:LinkButton
            id="lnkClear"
            Text="Clear Cart"
            OnClick="lnkClear_Click"
            runat="server" />
        </div>
    </form>
</body>
</html>

After you open the page in Listing 28.29, you should notice that each of the Web Parts displayed in the Product Zone includes the Add to Cart menu option. However, as soon as you move a Web Part to the Shopping Cart Zone, this menu option goes away.

Displaying Web Part Help

When you create True Web Parts, you have the option of adding a help menu option to the Web Part. You can set two properties related to help:

  • HelpUrl—. The URL of the help page to display.

  • HelpMode—. The user interface used when displaying the help page. Possible values are Modal, Modeless, and Navigate.

If you set HelpMode to the value Modal, then the help page opens in a modal window that you must close before returning to the original Web Part page. This option works only with Internet Explorer because it uses the Microsoft proprietary ShowModalDialog() statement.

The Web Part in Listing 28.30 displays a modal help page (see Figure 28.9).

Displaying Help for a Web Part.

Figure 28.9. Displaying Help for a Web Part.

Example 28.30. App_CodeConfusingPart.vb

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts

Namespace myControls
    ''' <summary>
    ''' This Web Part illustrates how to
    ''' use the HelpUrl and HelpMode properties
    ''' </summary>
    Public Class ConfusingPart
        Inherits WebPart

        Private _title As String = "Confusing Part"
        Private _helpUrl As String = "~/ConfusingPartHelp.aspx"
        Private _helpMode As WebPartHelpMode = WebPartHelpMode.Modal

        Public Overrides Property Title() As String
            Get
                Return _title
            End Get
            Set(ByVal Value As String)
                _title = value
            End Set
        End Property

        Public Overrides Property HelpUrl() As String
            Get
                Return _helpUrl
            End Get
            Set(ByVal Value As String)
                _helpUrl = value
            End Set
        End Property

        Public Overrides Property HelpMode() As WebPartHelpMode
            Get
                Return _helpMode
            End Get
            Set(ByVal Value As WebPartHelpMode)
                _helpMode = value
            End Set
        End Property

        Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
            writer.RenderBeginTag(HtmlTextWriterTag.H1)
            writer.Write("This Web Part is confusing")
            writer.RenderEndTag()
            writer.Write("Select the Help menu option for help")
        End Sub

    End Class
End Namespace

Notice that the Web Part in Listing 28.30 overrides both the HelpUrl and HelpMode properties.

Note

You can’t use the HelpUrl and HelpMode properties with a Generic Web Part. However, you can simulate the same user experience by adding a custom Help verb, which opens a new browser window, to the Generic Web Part.

Managing Web Parts with the WebPartManager Control

This final section of this chapter takes a closer look at the WebPartManager control. The WebPartManager control is responsible for tracking all the Web Parts in a page. It exposes the primary application programming interface for working with Web Parts.

The WebPartManager control supports the following particularly useful properties (this is not a complete list):

  • AvailableTransformers—. Represents all the transformers available on the page. Transformers are used when you connect incompatible Web Parts.

  • Connections—. Represents all the connections between Web Parts in a page.

  • DisplayMode—. Represents the current Display mode.

  • DisplayModes—. Returns a collection of all the Display modes associated with the WebPartManager.

  • Personalization—. Represents the WebPartPersonalization class, which tracks personalization data.

  • SelectedWebPart—. Represents the Web Part that is currently selected on the page. For example, when you select a Web Part control’s Edit menu option, the Web Part becomes the selected Web Part.

  • SupportedDisplayModes—. Represents all the Display modes supported by the current page,

  • WebParts—. Represents all the Web Parts on the page,

  • Zones—. Represents of the Web Part Zones on the page,

Some of these properties require additional explanation. Both the DisplayModes and the SupportedDisplayModes properties return a collection of Web Part Display Modes. However, in some situations, the DisplayModes property returns more Display Modes than the SupportedDisplayModes property. For example, if a page does not include a Catalog Zone, then the SupportedDisplayModes property doesn’t return CatalogDisplayMode as one of its values.

You can take advantage of the SupportDisplayModes property to automatically populate a Menu control with the list of available Display Modes like this:

Sub Page_Load()
  If Not Page.IsPostBack Then
    For Each mode As WebPartDisplayMode in WebPartManager1.SupportedDisplayModes
      Menu1.Items.Add(new MenuItem(mode.Name))
    Next
  End If
End Sub

The Zones property represents all the WebPartZone controls on a page. However, it does not include tool zones such as Catalog or Editor Zones.

The WebPartManager control also supports a number of useful methods:

  • AddWebPart—. Enables you to add a new Web Part to a Web Part Zone.

  • CanConnectWebParts—. Enables you to determine whether two Web Parts can be connected in a page. This method optionally enables you to specify a Transformer for the connection.

  • CloseWebPart—. Enables you to close a Web Part.

  • ConnectWebParts—. Enables you to connect two Web Parts in a page. This method optionally enables you to specify a Transformer for the connection.

  • CreateWebPart—. Enables you to create a new Generic Web Part from a control.

  • DeleteWebPart—. Enables you to delete a Web Part from a page.

  • DisconnectWebParts—. Enables you to break the connection between two Web Parts.

  • ExportWebPart—. Enables you to export Web Part settings to XML.

  • GetConsumerConnectionPoints—. Enables you to get all the consumer connection points exposed by a Web Part.

  • GetCurrentWebPartManager—. Enables you to get a reference to a page’s WebPartManager control from any user control or component used in a page. This is a shared (static) method.

  • GetGenericWebPart—. Enables you to retrieve an existing Web Part as a Generic Web Part.

  • GetProviderConnectionPoints—. Enables you to get all the provider connection points exposed by a Web Part.

  • ImportWebPart—. Enables you to import Web Part settings from XML.

  • IsAuthorized—. Enables you to create an authorization filter.

  • MoveWebPart—. Enables you to move a Web Part between Web Part Zones, or change the position of a Web Part in a Web Part Zone.

Notice that everything that you can do from particular tool zones—such as Editor and Catalog Zones—you can do using the methods of the WebPartManager control.

For example, the page in Listing 28.31 illustrates how you can dynamically rearrange the Web Parts in a Web Part Zone every time the page is requested.

Example 28.31. DynamicWebParts.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">

    Private  Sub Page_PreRender()
        Dim rnd As Random =  New Random()
        Dim webPartToMove As WebPart = WebPartManager1.WebParts(rnd.Next(WebPartManager1.WebParts.Count))
        Dim NewZoneIndex As Integer =  rnd.Next(webPartToMove.Zone.WebParts.Count)
        WebPartManager1.MoveWebPart(webPartToMove, webPartToMove.Zone, NewZoneIndex)
    End Sub

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .column
        {
            width:400px;
            height:200px;
            margin-right:10px;
            border:solid 1px black;
            background-color: white;
        }
        html
        {
            background-color:#eeeeee;
        }
    </style>
    <title>Dynamic Web Parts</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        Runat="server" />

        <asp:WebPartZone
            id="FeaturedProductsZone"
            CssClass="column"
            Runat="server">
            <ZoneTemplate>
            <asp:Panel
                id="FeaturedBooks"
                Title="Featured Books"
                Runat="server">
                <ul>
                    <li>Blink</li>
                    <li>A Theory of Justice</li>
                </ul>
            </asp:Panel>
            <asp:Panel
                id="FeaturedMovies"
                Title="Featured Movies"
                Runat="server">
                <ul>
                    <li>Star Wars: Episode III</li>
                    <li>Blade Runner</li>
                </ul>
            </asp:Panel>
            <asp:Panel
                id="FeaturedMusic"
                Title="Featured Music"
                Runat="server">
                <ul>
                    <li>Black Eyed Peas</li>
                    <li>Coldplay</li>
                </ul>
            </asp:Panel>

            </ZoneTemplate>
        </asp:WebPartZone>

    </form>
</body>
</html>

In Listing 28.31, the MoveWebPart() method called in the Page_Load() event handler is used to randomly move one of the Web Parts in the Featured Products Zone to a new position (see Figure 28.10).

Randomly Positioning Web Parts.

Figure 28.10. Randomly Positioning Web Parts.

Finally, the WebPartManager control supports a number of useful events:

  • AuthorizeWebPart—. Raised when the WebPartManager control adds each Web Part to a page (and Web Parts are displayed in the Catalog Zone).

  • ConnectionsActivated—. Raised after a connection between two Web Parts is activated.

  • ConnectionsActivating—. Raised before a connection between two Web Parts is activated.

  • DisplayModeChanged—. Raised after the Web Part Display Mode is changed.

  • DisplayModeChanging—. Raised before the Web Part Display Mode is changed.

  • SelectedWebPartChanged—. Raised after a Web Part is selected (for example, selected for editing).

  • SelectedWebPartChanging—. Raised before a Web Part is selected (for example, selected for editing).

  • WebPartAdded—. Raised after a new Web Part is added to the page.

  • WebPartAdding—. Raised before a new Web Part is added to the page.

  • WebPartClosed—. Raised after a Web Part is closed.

  • WebPartClosing—. Raised before a Web Part is closed.

  • WebPartDeleted—. Raised after a Web Part is deleted.

  • WebPartDeleting—. Raised before a Web Part is deleted.

  • WebPartMoved—. Raised after a Web Part is moved.

  • WebPartMoving—. Raised before a Web Part is moved.

  • WebPartsConnected—. Raised after a Web Part is connected.

  • WebPartsConnecting—. Raised before a Web Part is connected.

  • WebPartsDisconnected—. Raised after a Web Part is disconnected.

  • WebPartsDisconnecting—. Raised before a Web Part is disconnected.

Notice that most of these events come in pairs. There is a DisplayModeChanging event and a DisplayModeChanged event. You can cancel the action associated with most of these events within the ing event handler.

The page in Listing 28.32 handles the WebPartClosed event to display an informational message after a user closes a Web Part.

Example 28.32. ShowCloseWarning.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">

    Protected Sub WebPartManager1_WebPartClosed(ByVal sender As Object, ByVal e As WebPartEventArgs)
        divCloseWarning.Visible = True
    End Sub

    Protected 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">
        .divCloseWarning
        {
            position:absolute;
            background-color:#eeeeee;
            padding:15px;
            left:200px;
            top:50px;
            border:double 3px red;
            width:200px;
        }
        .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>Show Close Warning</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:WebPartManager
        id="WebPartManager1"
        OnWebPartClosed="WebPartManager1_WebPartClosed"
        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="FeaturedProductsZone"
        CssClass="column"
        Runat="server">
        <ZoneTemplate>
        <asp:Label
            id="Label1"
            Title="First Web Part"
            Text="Contents of First Web Part"
            Runat="server" />
        <asp:Label
            id="Label2"
            Title="Second Web Part"
            Text="Contents of Second Web Part"
            Runat="server" />
        </ZoneTemplate>
    </asp:WebPartZone>

    <div
        id="divCloseWarning"
        class="divCloseWarning"
        Visible="false"
        Enableviewstate="false"
        Runat="server">
        You have closed a Web Part. You
        can reopen the Web Part by opening
        the Page Catalog.
        <br /><br />
        <asp:Button
            id="btnOK"
            Text="OK"
            Runat="server" />
    </div>

    <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 28.32, you can close a Web Part by selecting a Web Part control’s Close menu option. When you close a Web Part, an informational message appears (see Figure 28.11).

Displaying a Close warning.

Figure 28.11. Displaying a Close warning.

Summary

In this chapter, you learned how to build Web Parts. We started by creating two Hello World Web Parts. One Web Part was created with a User Control, and the other Web Part was created with a control that inherits from the base WebPart class.

Next, you learned how to create authorization filters for Web Parts. You learned different methods of filtering Web Parts so that different users can view different sets of Web Parts on the same page.

You also learned how to add custom verbs (menu items) to a Web Part. You learned how to associate both server-side and client-side code with a verb.

We also discussed the important topic of adding help to a Web Part. You learned how to open a modal dialog box that displays help information for a particular Web Part.

Finally, the Web Part application programming interface exposed by the WebPartManager control was explored in detail. You learned how to manipulate the Web Parts contained in a page through the methods of the WebPartManager class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset