Pro ASP.NET 2.0 In CSharp 2005 (2005) [eng]
.pdf
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
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
//...
