Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro ASP.NET 2.0 In CSharp 2005 (2005) [eng]

.pdf
Скачиваний:
106
Добавлен:
16.08.2013
Размер:
29.8 Mб
Скачать

1068 CHAPTER 31 PORTALS WITH WEB PART PAGES

The Final Rendering

You have now initialized the WebPart, created controls, wrote code for loading data, and caught control events. So, it’s time to render the WebPart. Immediately before you render the WebPart, you can set final property values on your controls that affect rendering. For example, you should disable the InsertNewNote button if the user has not initialized the Customer property. And of course the GridView can now create the necessary HTML controls for displaying the data to which it is bound. To do this, you need to call the DataBind method as follows:

void CustomerNotesPart_PreRender(object sender, EventArgs e)

{

if (Customer.Equals(string.Empty)) InsertNewNote.Enabled = false;

else

InsertNewNote.Enabled = true;

CustomerNotesGrid.DataBind();

}

In the RenderContents method, you can create the HTML code to lay out your WebPart. If you don’t override the method, the WebPart automatically renders the previously added controls in the order they have been inserted into the WebPart’s Controls collection within the CreateChildControls method. Because this layout is simple (just a sequence of the controls), you will now override the RenderContents method to create a better, table-based layout, as follows:

protected override void RenderContents(HtmlTextWriter writer)

{

writer.Write("<table>");

writer.Write("<tr>");

writer.Write("<td>");

NewNoteText.RenderControl(writer);

InsertNewNote.RenderControl(writer);

writer.Write("</td>");

writer.Write("</tr>");

writer.Write("<tr>");

writer.Write("<td>");

CustomerNotesGrid.RenderControl(writer);

writer.Write("</td>");

writer.Write("</tr>");

writer.Write("</table>");

}

This code renders an HTML table through the HtmlTextWriter with two rows and one column. The first row contains the text box and the button, and the second row contains the GridView with the notes. Finally, the method uses the RenderControl method of the child controls to render the text box, button, and grid in a specific position within the table. Therefore, you have easily overridden the default rendering of the WebPart base class.

More Customization Steps

As previously shown, with the IWebPart interface a custom WebPart implemented this way can override properties such as the title or description. Furthermore, you can specify default values for

CHAPTER 31 PORTALS WITH WEB PART PAGES

1069

other properties of the WebPart by just setting the values for them (which works best in the Load method). You can even override the implementations of default properties and methods from the WebPart. The following example shows how you can initialize the WebPart and override WebPart properties:

void CustomerNotesPart_Load(object sender, EventArgs e)

{

// Initialize Web Part Properties this.Title = "Customer Notes"; this.TitleIconImageUrl = "NotesImage.jpg";

}

public override bool AllowClose

{

get

{

return false;

}

set

{

// Don't want this to be set

}

}

This code initializes some of the WebPart’s properties in the Load event with default values. It then overrides the AllowClose property to always return false, and it ignores any set operation by just leaving the logic here. This way, you have created a WebPart where the caller cannot override this behavior by just setting this property from outside. You really have complete customization and control over what can and can’t be done with your WebPart. This is the sort of power you can never get when working with user controls.

Using the WebPart

Now you can take a close look at the details of your WebPart. To do this, register the WebPart on your web part page using the <%@ Register%> directive at the top of the web page, as follows:

<%@ Register TagPrefix="apress" Namespace="Apress.WebParts.Samples" %>

Remember that you used the namespace Apress.WebParts.Samples in the class file of the custom web part. The <%@ Register %> directive assigns the prefix Apress to this namespace. Therefore, you can use the web part in one of the previously created WebPartZone controls, as follows:

<asp:WebPartZone runat="server" ID="MainZone"> <ZoneTemplate>

<uc1:Customers ID="MyCustomers"

runat="server" OnLoad="MyCustomers_Load" />

<apress:CustomerNotesPart ID="MyCustomerNotes" runat="server" />

</ZoneTemplate>

</asp:WebPartZone>

Now you can test your newly created web part by starting your web application. Figure 31-11 shows the results of your work.

1070 CHAPTER 31 PORTALS WITH WEB PART PAGES

Figure 31-11. The custom web part in action with the other web parts

Web Part Editors

In the previous example, you created a custom WebPart with a personalizable property called Customer. This property determined whether the content of the GridView in the WebPart displays information for just one customer or for all customers. You were not able to change this property through the web part page’s user interface, so you will now see how you can accomplish this.

Basically, the ASP.NET 2.0 Web Part Framework provides functionality for editing properties of WebParts. As you saw when creating the Menu control for switching the page’s DisplayMode, it includes an Edit mode. However, if you try to activate it now, you will get an exception about missing controls on the page. The missing pieces for the Edit mode are the EditorWebZone and some appropriate editor parts. Both are prebuilt; the WebPartZone hosts editor parts. You can use them by adding an EditorZone and one of the prebuilt editor parts to your page, as follows:

<asp:EditorZone runat="server" ID="SimpleEditor"> <ZoneTemplate>

<asp:AppearanceEditorPart ID="MyMainEditor" runat="server" /> </ZoneTemplate>

</asp:EditorZone>

This code adds an AppearanceEditorPart to the zone, which allows you to configure the appearance of the WebPart including its title and chrome settings (see Table 31-2). Now you can switch to the Edit mode on your page; Figure 31-12 shows the steps required for opening an appropriate editor on your page.

CHAPTER 31 PORTALS WITH WEB PART PAGES

1071

Figure 31-12. Editing properties of your web parts

Table 31-4 lists the available editor WebParts of the framework.

The PropertyGridEditorPart editor part is a suitable way to enable the user to modify the previously implemented Customer property of your web part. Just add the editor part to your page as follows, and edit your custom WebPart:

<asp:EditorZone runat="server" ID="SimpleEditor"> <ZoneTemplate>

<asp:PropertyGridEditorPart ID="MyPropertyEditor" runat="server" />

<asp:AppearanceEditorPart ID="MyMainEditor" runat="server" /> </ZoneTemplate>

</asp:EditorZone>

1072 CHAPTER 31 PORTALS WITH WEB PART PAGES

Table 31-4. Editor WebParts Shipping with ASP.NET 2.0

Editor Part

Description

AppearanceEditorPart

Allows you to configure basic properties of the WebPart including its

 

title and its ChromeStyle.

BehaviorEditorPart

Includes editors for modifying properties that affect the behavior of

 

the WebPart. Typical examples of such properties are the AllowClose

 

or AllowMinimize properties as well as properties such as TitleUrl,

 

HelpMode, and HelpUrl. Every property modifies behavior such as

 

whether the WebPart can be minimized.

LayoutEditorPart

Allows the user to change the WebPart’s zone as well as its

 

ChromeState. By the way, this editor enables browsers where

 

changing a WebPart’s zone through dragging and dropping

 

doesn’t work manually through the controls of this editor part.

PropertyGridEditorPart

Displays a text box for every public property of your custom WebPart

 

that includes the attribute [WebBrowsable(true)].

 

 

Figure 31-13 shows the results. As soon as you switch to the Edit mode and edit your custom WebPart, you can change the value for the Customer property.

Figure 31-13. The PropertyGridEditorPart in action

Because you have called BindGrid in the property’s set method previously, the appearance of the WebPart changes as soon as you hit the Apply button of the EditorZone. Additionally, if you add a [WebDisplayName] in addition to the [WebBrowsable] attribute to your custom property, you can control the name of the property that the editor will display.

CHAPTER 31 PORTALS WITH WEB PART PAGES

1073

Creating a Custom Editor

Displaying a text box, where the user has to manually enter the customer ID, to select a customer is not a great ergonomic solution. Creating a custom editor that enables the user to select the customer from a list would be more helpful. That’s what you’ll learn in this section.

Creating a custom editor for a web part page is as easy as creating a custom web part or a custom server control. The only difference is that you need to inherit from EditorPart instead of WebPart or WebControl, as follows:

public class CustomerEditor : EditorPart

{

public CustomerEditor()

{

//

// TODO: Add constructor logic here

//

}

public override bool ApplyChanges()

{

// Apply changes to the WebPart's property

}

public override void SyncChanges()

{

// Initialize EditorPart with values from WebPart

}

}

Again, because the custom editor is nothing more than a composite control, you can add child controls by overriding the CreateChildControls method. In this case, you need to create a list for displaying the customers available in the database, as follows:

private ListBox CustomersList;

protected override void CreateChildControls()

{

CustomersList = new ListBox(); CustomersList.Rows = 4;

Controls.Add(CustomersList);

}

Now that you have created the list, you can load the data in the initialization phase of the EditorPart control. Again, assuming you have already a typed DataSet for working with customers in place, you can catch the Load event and then load the customers, as follows:

public CustomerEditor()

{

this.Init += new EventHandler(CustomerEditor_Init);

}

void CustomerEditor_Init(object sender, EventArgs e)

{

EnsureChildControls();

1074 CHAPTER 31 PORTALS WITH WEB PART PAGES

CustomerTableAdapter adapter = new CustomerTableAdapter();

CustomersList.DataSource = adapter.GetData();

CustomersList.DataTextField = "CompanyName";

CustomersList.DataValueField = "CustomerID";

CustomersList.DataBind();

// Empty selection to show all notes CustomersList.Items.Insert(0, "");

}

Finally, you have to synchronize changes between the EditorPart and the actual WebPart. First we’ll show how to retrieve information from the WebPart. To do this, you have to add code to your SyncChanges method, which you have to override when inheriting from EditorPart. Within this method, you get access to the WebPart that will be edited through the base class’s WebPartToEdit property. Of course, then you have access to all the properties of your WebPart as usual.

public override void SyncChanges()

{

//Make sure that all controls are available EnsureChildControls();

//Get the property from the WebPart

CustomerNotesPart part = (CustomerNotesPart)WebPartToEdit; if (part != null)

{

CustomersList.SelectedValue = part.Customer;

}

}

When the user updates the value in the editor by clicking Apply, you have to update the WebPart’s property. You can do this in the ApplyChanges method, where again you can access the WebPart through the base class’s WebPartToEdit property, as follows:

public override bool ApplyChanges()

{

//Make sure that all controls are available EnsureChildControls();

//Get the property from the WebPart

CustomerNotesPart part = (CustomerNotesPart)WebPartToEdit; if (part != null)

{

if (CustomersList.SelectedIndex >= 0) part.Customer = CustomersList.SelectedValue;

else

part.Customer = string.Empty;

}

else

{

return false;

}

return true;

}

The method returns true if the value has been updated successfully and returns false otherwise. Basically, that’s it—you have created a custom editor. But how can you use it? Somehow the infrastructure has to know that this editor has to be used with only specific WebParts—in this case

CHAPTER 31 PORTALS WITH WEB PART PAGES

1075

with the CustomerNotesPart. To do this, modify the originally created WebPart. It has to implement the IWebEditable interface as follows:

public class CustomerNotesPart : WebPart, IWebEditable

{

#region IWebEditable Members

EditorPartCollection IWebEditable.CreateEditorParts()

{

// Create editor parts

List<EditorPart> Editors = new List<EditorPart>(); Editors.Add(new CustomerEditor());

return new EditorPartCollection(Editors);

}

object IWebEditable.WebBrowsableObject

{

get { return this; }

}

#endregion

// Rest of the implementation

...

This method works for user controls and server controls. The GenericWebPart that wraps user controls and server controls verifies whether the wrapped control implements the IWebEditable interface. If the control implements the interface, it calls the control’s implementation of the interface for providing the custom editors. The CreateEditorParts just returns a collection of EditorParts to be displayed for this WebPart, and the WebBrowsableObject returns the class that contains the personalizable properties. Figure 31-14 shows the results.

Figure 31-14. The custom editor part in action

1076 CHAPTER 31 PORTALS WITH WEB PART PAGES

Connecting Web Parts

WebParts can also exchange information in a well-defined manner. For example, a web part that displays a list of customers could notify another web part (or many other web parts) if a specific customer has been selected so that this other WebPart can display information according to the selection in the customer WebPart. The ASP.NET framework lets you create such “connectable” WebParts and offers the possibility of statically or dynamically connecting WebParts. For creating connectable WebParts, you have to create and combine several pieces. Figure 31-15 shows these pieces and how they relate to each other.

Figure 31-15. The pieces for creating connectable web parts

You can see that Figure 31-15 has two primary types of WebParts: providers make information available to other WebParts, and every WebPart that requires information from a provider WebPart is a consumer WebPart. Finally, you have to establish a standardized way for exchanging the information, which leads to the final missing piece, the communication contract. Technically, the communication contract is an interface that has to be implemented by the provider WebPart. This interface defines how a consumer WebPart can access information from the provider WebPart. In other words, the provider WebPart makes its data available through this interface. The steps for creating and connecting WebParts are as follows:

1.Create a communication contract: The first thing you should think about is, which information needs to be exchanged? Based on the response to this question, you can design an interface for data exchange that has to be implemented by the provider web part.

2.Create a provider WebPart: Next you can create the provider WebPart. This WebPart has to perform two tasks: it needs to implement the previously defined communication contract interface or know a class implementing this interface, and it needs to provide a method that returns an instance of a class implementing the interface. This method must be marked with the [ConnectionProvider] attribute.

3.Create a consumer WebPart: Next, you can create a consumer WebPart. The consumer WebPart does not need to implement any interfaces, but it needs to know how to communicate to the provider. Therefore, it needs to know about the interface (which means if you have the consumer in a separate DLL, it needs to reference an assembly that defines this interface). A consumer WebPart then needs to implement a method that is marked with

the [ConnectionConsumer] attribute. This method accepts a variable as a parameter that implements the previously defined communication contract interface.

CHAPTER 31 PORTALS WITH WEB PART PAGES

1077

4.Configure the connection: Finally, you have to configure the connection between the consumer and the provider WebPart. You can do that statically through the <StaticConnections> section within the WebPartManager, or the user can configure connections at runtime. You will learn more details about how to implement both ways later in the “Static Connections Between WebParts” section.

You can connect only WebParts inherited from WebPart; because user controls and custom server controls are wrapped by the GenericWebPart, the framework has no direct access to the methods marked with the [ConnectionProvider] and [ConnectionConsumer] attributes.

Previously you created a WebPart for displaying customer notes in a grid. Because notes can get long (remember, the column is a text column), it might be nice to have a larger text box for editing the value of this field. To learn about WebPart connections, in the next sections you will create a simple WebPart that displays the text for the notes, and then you will modify the old WebPart to become a provider WebPart.

Defining the Communication Contract

The first step is to design the communication contract. Because your WebPart will provide just simple text and date information, the communication contract is fairly simple:

namespace Apress.WebParts.Samples

{

public interface INotesContract

{

string Notes { get; set; } DateTime SubmittedDate { get; }

}

}

This contract defines two properties: one for retrieving and updating the notes text for a customer and the second for retrieving the date of a submitted entry. Now the provider has to implement this interface, while the consumer has just to know about the interface.

Implementing the Provider

As the provider WebPart will be the previously created CustomerNotesPart, you need to modify this one so it implements the INotesContract communication contract interface and contains a public method with the [ConnectionProvider] attribute. Basically, the code is as follows:

public class CustomerNotesPart

: WebPart, IWebEditable, INotesContract

{

#region INotesContract Members

public string Notes

{

get

{

//Get the NoteContent value from the grid's data source

//...

}

set

{

//Update value to the grid's data source

//...