Connecting WebParts Together


We've used the example of a weather WebPart several times in this chapter, and in early examples this used a ZipCode property to state the location to display the weather for. A better solution would be to have the Zip Code supplied to the WebPart, perhaps by another WebPart. This is achieved by WebPart connections, where data can be supplied directly from one part to another.

WebPart connection revolves around providers that supply data and consumers that use data. Both providers and consumers use a common interface to define the data being passed between them, and the WebPartManager manages the connection. Figure 13.15 shows the flow of data between the provider and consumer, and how the WebPartManager controls this.

Figure 13.15. WebPart Connections data flow


The steps are:

1.

The WebPartManager calls a method on the Provider.

2.

The WebPartManager receives the provider interface.

3.

The WebPartManager passes the interface to the Consumer.

4.

The Consumer calls the Provider using the supplied interface.

Implementing WebPart Connections

Implementing connections requires an interface to define the data and for a Provider to implement that interface. The Consumer doesn't need to implement the interface but will require a reference to it, because it is the interface that is used to pass the data.

Creating the Interface

The first part of implementing WebPart connections is to create an interface that defines the data. For example, the weather WebPart requires a Zip Code, the interface for which is defined in Listing 13.15.

Listing 13.15. The Zip Code Interface

public interface IZipCode {   string ZipCode { get; } }

This simply defines a read-only property, ZipCode, which is the only piece of data needed. The interface can be more complex, containing properties and methods, providing a great deal of flexibility when connecting WebParts.

Implementing the Interface in the Provider

Within the provider, the interface is implemented to supply the data to consumers. In our example, the Contacts WebPart is a Provider and is also a user control. The code-behind for this user control is shown in Listing 13.16, where the IZipCode interface is implemented.

There are some important points to notice about this code:

  • The interface implementation simply returns the details of a cell from a DetailsView control. If your interface requires more information, you simply implement those, perhaps more, properties, or even returning more complex types.

  • A method, ProvideIZipCode, returns the current instance of the object implementing the interface. This is used by the WebPartManager to fetch the interface, where it can be passed to the Consumer.

  • The ProvideIZipCode method is decorated with the ConnectionProvider attribute to indicate this is a Provider of connection information. When connections are made, the values defined in the attribute are used; the first value is the description, and the second is the name of the connection pointthe connection point is a specific point within a Provider that provides a connection interface, and giving explicit names allows multiple connection points.

Listing 13.16. Creating the Provider

public partial class ch13_Contacts :   System.Web.UI.UserControl, IWebPart, IZipCode {   #region IWebPart Members   ...   #endregion   #region IZipCode Members   public string ZipCode   {     get { return DetailsView1.Rows[10].Cells[1].Text; }   }   [ConnectionProvider("Zip Code", "ZipCodeProvider")]   public IZipCode ProvideIZipCode()   {     return this;   }   #endregion }

Using the Interface in the Consumer

Within the Consumer, the interface isn't implemented. Instead, a connection end point is defined that accepts an instance of the interface, as shown in Listing 13.17.

Listing 13.17. Consuming the Connection Interface

private IZipCode _provider; [ConnectionConsumer("Zip Code", "ZipCodeConsumer",    AllowsMultipleConnections=true)] public void GetIZipCode(IZipCode provider) {     _provider = provider; }

Here there is a method that takes a single parameter of type IZipCodethe interface. The WebPartManager receives the interface from the Provider and passes it to the Consumer using this method. In the example code, the interface is simply stored in a variable for later use (which we'll come to in a moment). The Consumer method is also decorated with an attribute, in this case the ConnectionConsumer attribute, the parameters of which are the description, the connection point name, and optionally, whether multiple connections can be made to this end point.

Listing 13.18 shows how the Consumer uses the interface from the Provider. First it is checked for a null value, which would indicate there is no connection in place. If the connection is in place, the property defined by the interface is accessed to fetch the data from the Provider; in this example it is used to format a query to the Yahoo weather RSS feed, which supplies a forecast for several days.

Listing 13.18. Using the Data from the Provider

if (_provider != null) {   string qry = string.Format(     "http://xml.weather.yahoo.com/forecastrss?p={0}",     _provider.ZipCode);

Once the interface and end points have been defined, you need to connect the WebParts together.

Connections between WebParts can be static or dynamic. Static connections are defined by the page creator, while dynamic connections are created by the user at runtime. Static connections are created within the StaticConnections section of the WebPartManager, as shown in Listing 13.19.

The connection details are defined in four properties of the WebPartConnection:

  • ConsumerConnectionPointID, which is the name of the connection point on the Consumer. This is the name defined in the ConnectionConsumer attribute

  • ConsumerID, which is the ID of the WebPart acting as the Consumer. In this example, it is the custom server control with the ID of yWeatherWebPart

  • ProviderConnectionPointID, which is the name of the connection point on the Provider. This is the name defined in the ConnectionProvider attribute

  • ProviderID, which is the ID of the WebPart acting as the Provider. In this example, it is the User Control with the ID of Contacts1

Listing 13.19. Creating Static Connections

<asp:WebPartManager  runat="server"   Personalization-Enabled="true"   OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart">   <StaticConnections>     <asp:WebPartConnection          ConsumerConnectionPoint         Consumer         ProviderConnectionPoint         Provider         />   </StaticConnections> </asp:WebPartManager>

Because this connection is permanent, data will be supplied from the Provider to the Consumer as long as both parts are on the page. For example, consider Figure 13.16, which shows the Contacts and Weather WebParts, which are connected, even though it doesn't appear to be so. The reason is that the data provided is for the DetailsView, and no contact is currently selected.

Figure 13.16. Connected WebParts (with no data selected)


If a contact is selected, data is available to be provided to the Consumer, so the weather details automatically show.

User-Initiated Connections

You can allow users to connect parts together or to disconnect WebParts (even statically created ones) by using a ConnectionsZone, as shown in Listing 13.20.

Listing 13.20. Declaring a ConnectionsZone

<asp:ConnectionsZone    runat="server" />

When the DisplayMode of the page is set to ConnectDisplayMode, the Connect verb is added to the verbs for WebParts. Selecting this displays the ConnectionsZone, the contents of which depend upon the current connection state of the WebPart (see Figure 13.17). For a WebPart with no current connections, you would see a message indicating that no connections are present, with a link to create a connection. For example, Figure 13.18 shows the connection zone for a Provider that has no active connections.

Figure 13.17. Connected WebParts (with data selected)


Figure 13.18. The Connections Zone for a Provider with no active connections


For a WebPart with connections, you see the current connections (with an option to delete them), as well as the link to create connections, as shown in Figure 13.19. This shows the Contacts WebPart with a connection to the My Weather WebPart, sending the Zip Code (the description for the data being sent is taken from the ConnectionProvider attribute). For providers, the interface has the same layout but with the appropriate name changes (see Figure 13.20).

Figure 13.19. The Connections Zone for a Provider with active connections


Figure 13.20. Connections Zone for a Consumer with active connections


Whether on a Provider or Consumer, clicking Disconnect will remove the connection between the WebParts. Clicking the Connect link allows connection to a WebPart. For example, Figure 13.21 shows connecting from the Consumergetting data from the Contacts WebPart, and Figure 13.22 shows the opposite, connecting from a Providersending data to the Weather WebPart.

Figure 13.21. Connecting to a Provider


Figure 13.22. Connecting to a Consumer


WebParts can be both Providers and Consumers, consuming or supplying data from a number of WebParts.

Connecting to WebParts in Master Pages

When using Master Pages, you will generally have the WebPartManager on the Master Page. If you wish to define connections between WebParts on the Master Page and the content page, then you need to use a ProxyWebPartManager on the content page, as shown in Listing 13.21.

Listing 13.21. Declaring a ProxyWebPartManager

<asp:ProxyWebPartManager  runat="server">   <StaticConnections>     <asp:WebPartConnection        Consumer       Provider>     </asp:WebPartConnection>   </StaticConnections> </asp:ProxyWebPartManager>

The ProxyWebPartManager, as its name suggests, is simply a proxy to the WebPartManager on the Master Page.

Transformers

When connecting WebParts, you obviously aim for flexibility, and perhaps you want a WebPart to either provide or consume a variety of different data types. If writing your own WebParts, this is easy to achieve since you can add the types to the interface, but if using third-party WebParts, you may have to deal with data in formats you aren't expecting. The solution to this is to provide transformers, which transform data from one type to another.

A transformer is a class that converts data between types exposed by interfacesthe interfaces that Consumers and Providers use. For example, consider two WebParts that expose data via interfaces, one of which exposes integer data while the other exposes string data. By default, you would not be able to connect these, because the data types are incompatible. However, by creating a transformer, you can transform the data as it flows between the WebParts. To make this easy to understand, consider two WebParts, one that provides string data, and one that consumes integer data. While it is easy to convert between these two, the principles of a transformer are easier to understand with simple types, and the technique can be applied between any types. For example, consider Listing 13.22, which implements a WebPartTrasnformer, converting data from a string provider to an integer consumer.

The transformer is identified by the WebPartTransformer attribute, which defines the type to convert from and the type to convert to. The class inherits from WebPartTransformer and implements the IIntegerData interfacethe interface used by the consumer. The TRansform method provides access to the string data, and the implementation if the IIntegerData interface simply converts the data from this interface.

Listing 13.22. A Sample Transformer

[WebPartTransformer(typeof(IStringData), typeof(IIntegerData))] public class IntegerToStringTransformer :   WebPartTransformer, IIntegerData {   IStringData _stringData;   /// <summary>   /// Transforms from IFoo to IBar   /// </summary>   public override object Transform(object providerData)   {     _stringData = (IStringData)providerData;     return this;   }   #region IIntegerData Members   public int IntegerData   {     get     {       if (_stringData.StringData != null)       {         try         {           return int.Parse(_stringData.StringData);         }         catch { }       }       return -1;     }   }   #endregion }

Before a transformer can be used, it must be defined in the webParts transformers section of web.config. The type should be set to the full type name of the transformer.

Listing 13.23. Configuring the Transformer

<webParts enableExport="true">   <transformers>     <add name="String to Integer Transformer"       type="Sample.Web.UI.IntegerToStringTransformer"/>   </transformers> </webParts>

At runtime, the transformer is injected into the connection between WebParts, first by allowing the connection to take place (because the transformer converts between incompatible types) and then by providing the actual conversion process. The great point about this is that the technique can be used for converting data from third party WebParts without having to get the third party to expose (or consume) data in a form it doesn't require. You can write the transformer yourself, integrating previously incompatible WebParts.



ASP. NET 2.0 Illustrated
ASP.NET 2.0 Illustrated
ISBN: 0321418344
EAN: 2147483647
Year: 2006
Pages: 147

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net