13.7 将WebPart连接在一起
本章中多次使用了一个天气WebPart的例子,在前面的例子中,使用了ZipCode属性来指出显示哪个位置的天气。更好的解决方案是向WebPart提供邮政编码,它可能由另一个WebPart提供。这是通过WebPart连接实现的,其中数据可以从一个WebPart直接提供给另一个WebPart。
WebPart连接围绕着两方面,一方面是提供数据的提供者,另一方面是使用数据的消费者。提供者和消费者都使用一个公共接口来定义在它们之间传递的数据,并由WebPartManager管理连接。图13-15显示了提供者和消费者之间的数据流,并显示了WebPartManager对此如何控制。
|
|
|
图13-15 WebPart连接数据流
步骤如下:
(1)WebPartManager调用提供者上的一个方法。
(2)WebPartManager接收提供者接口。
(3)WebPartManager将接口传递给消费者。
(4)消费者使用所提供的接口调用提供者。
13.7.1 实现WebPart连接
实现连接时,需要一个接口来定义数据,而且要求提供者实现这个接口。消费者不需要实现这个接口,但是需要接口的一个引用(因为要用这个接口来传递数据)。
1. 创建接口
实现WebPart连接时,首先是创建一个定义数据的接口。例如,天气WebPart需要一个邮政编码,其接口定义见代码清单13-15。
代码清单13-15 邮政编码接口
public interface IZipCode
{
string ZipCode { get; }
}
这只是定义了一个只读属性ZipCode,这是唯一需要的数据。接口还可以更复杂,包含其他属性和方法,从而在连接时提供更大的灵活性。
2. 提供者中实现这个接口
提供者要实现这个接口向消费者提供数据。在这个例子中,Contacts WebPart是一个提供者,这也是一个用户控件。这个用户控件的后台代码如代码清单13-16所示,这里实现了IZipCode接口。
代码清单13-16 创建提供者
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
}
关于这段代码有几个要点需要注意:
q 这个接口实现只是返回DetailsView 控件中一个单元格的详细信息。如果接口需要更多的信息,只需实现这些属性,或者甚至可以返回更复杂的类型。
q ProvideIZipCode方法返回实现此接口的对象的当前实例。WebPartManager使用这个实例来获取接口,从而将其传递给消费者。
q ProvideIZipCode方法带有ConnectionProvider性质,指示这是连接信息的提供者。建立连接时,会使用这个性质中定义的值。第一个值是描述,第二个是连接点的名(连接点是提供连接接口的提供者中的一个特定点,通过指定显式的名允许有多个连接点)。
3. 在消费者中使用接口
消费者并不实现接口。相反,它会定义一个连接端点来接受接口的一个实例,如代码清单13-17所示。
代码清单13-17 使用连接接口
private IZipCode _provider;
[ConnectionConsumer("Zip Code", "ZipCodeConsumer",
AllowsMultipleConnections=true)]
public void GetIZipCode(IZipCode provider)
{
_provider = provider;
}
这里有一个方法GetIZipCode,它取一个IZipCod类型(接口)的参数。WebPartManager从提供者接收接口,并使用这个方法将接口传递给消费者。在示例代码中,这个接口只是存储在一个变量中以便以后使用(稍后将介绍)。消费者方法也带了一个属性,不过这里是一个ConnectionConsumer属性。其参数也包括描述和连接点名,另外还有一个可选的参数指示是否能对这个端点建立多个连接。
代码清单13-18显示了消费者如何使用提供者传递的这个接口。首先它检查这个接口是否为null值,如果是null,说明当前没有连接。如果已经有连接,则访问接口定义的属性,从提供者获取数据。在这个例子中,会使用这个数据建立对Yahoo天气RSS提要的一个查询,这会提供数天的天气预报。
代码清单13-18 使用从提供者获取的数据
if (_provider != null)
{
string qry = string.Format(
"http://xml.weather.yahoo.com/forecastrss?p={0}",
_provider.ZipCode);
一旦定义了接口和端点,下面需要将WebPart连接在一起。
13.7.2 连接WebPart
WebPart之间的连接可以是静态或动态连接。静态连接由设计页面的人定义,而动态连接由用户在运行时创建。静态连接在WebPartManager的StaticConnections元素中建立,如代码清单13-19所示。
代码清单13-19 创建静态连接
<asp:WebPartManager ID="WebPartManager1" runat="server"
Personalization-Enabled="true"
OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart">
<StaticConnections>
<asp:WebPartConnection ID="connection1"
ConsumerConnectionPointID="ZipCodeConsumer"
ConsumerID="yWeatherWebPart"
ProviderConnectionPointID="ZipCodeProvider"
ProviderID="Contacts1"
/>
</StaticConnections>
</asp:WebPartManager>
连接的详细信息在WebPartConnection的4个属性中定义:
q ConsumerConnectionPointID, 消费者上的连接点名。这是ConnectionConsumer属性中定义的名。
q ConsumerID, 作为消费者的WebPart的ID。在这个例子中,消费者就是ID为yWeatherWebPart的定制服务器控件。
q ProviderConnectionPointID, 提供者上的连接点名。这是ConnectionProvider属性中定义的名。
q ProviderID, 作为提供者的WebPart的ID。在这个例子中,提供者就是ID为Contacts1的用户控件。
由于这个连接是永久的,数据会从提供者提供到消费者(只要提供者和消费者都在页面上)。例如,考虑图13-16,这里显示了Contacts和Weather WebPart,尽管看上去并非如此,它们实际上已经连接。原因在于所提供的数据来自DetailsView,而当前没有选择签约方。

图13-16 已连接的WebPart(没有选择数据)
如果选择了一个签约方,数据就可以提供给消费者,从而自动显示天气的详细信息。
13.7.3 用户发起的连接
可以让用户将两个WebPart连接起来,或者断开WebPart的连接(甚至断开静态创建的WebPart连接),为此要使用一个ConnectionsZone,如代码清单13-20所示。
代码清单13-20 声明一个ConnectionsZone
<asp:ConnectionsZone
ID="ConnectionsZone1" runat="server" />
页面的DisplayMode设置为ConnectDisplayMode时,Connect verb会增加到WebPart的verbs菜单。选择这个模式会显示ConnectionsZone,其内容取决于WebPart的当前连接状态(参见图13-17)。对于一个没有当前连接的WebPart,会看到一个消息指示当前没有连接,并有一个链接可以创建连接。例如,如果一个提供者没有活动连接,其连接区域如图13-18所示。

图13-17 已连接的WebPart(选择了数据)

图13-18 无活动连接的提供者的连接区域
对于有连接的WebPart,可以看到当前连接(提供了选项可以将连接删除),还可以看到创建连接的链接,如图13-19中所示。这里显示了将发送邮政编码的Contacts WebPart(所发送数据的描述取自ConnectionProvider属性),它与My Weather WebPart有一个连接。对于提供者,界面布局相同,但是名字会适当调整(参见图13-20)。
|
|
|
|
图13-19 有活动连接的提供者的连接区域 |
图13-20 有活动连接的消费者的连接区域 |
不论在提供者上还是消费者上,点击Disconnect都会删除WebPart之间的连接。点击Connect链接则建立与一个WebPart的连接。例如,图13-21显示了消费者的连接,它从Contacts WebPart获得数据,图13-22则相反,显示了提供者的连接,向Weather WebPart发送数据。
|
|
|
|
图13-21 连接一个提供者 |
图13-22 连接一个消费者 |
WebPart既可以作为提供者也可以作为消费者,可以使用来自多个WebPart的数据,也可以向多个WebPart提供数据。
13.7.4 连接到母版页中的WebPart
使用母版页时,通常在母版页上会有WebPartManager。如果希望在母版页和内容页上的WebPart之间定义连接,则需要在内容页上使用一个ProxyWebPartManager,如代码清单13-21所示。
代码清单13-21 声明一个ProxyWebPartManager
<asp:ProxyWebPartManager ID="ProxyWebPartManager1" runat="server">
<StaticConnections>
<asp:WebPartConnection ID="MyFirstConnection"
ConsumerID="yWeatherWebPart"
ProviderID="Contacts1">
</asp:WebPartConnection>
</StaticConnections>
</asp:ProxyWebPartManager>
顾名思义,ProxyWebPartManager就是母版页上WebPartManager的一个代理。
13.7.5 转换器
连接WebPart,显然希望更为灵活,你可能希望一个WebPart能提供多种不同的数据类型,或者能使用多种不同的数据类型。如果编写自己的WebPart,这很容易实现,因为可以向接口增加类型,但是如果使用第三方WebPart,则可能必须处理你不曾预见到的其他格式的数据。对此的解决方案是提供转换器,将数据从一种类型转换为另一种类型。
转换器是一个在接口(消费者和提供者使用的接口)提供的类型之间完成数据转换的类。例如,考虑两个通过接口提供数据的WebPart,其中一个提供整数数据,另一个提供串数据。默认,二者无法连接,因为数据类型不兼容。不过,通过创建一个转换器,数据在WebPart之间流动时就可以转换数据。为了便于理解,请考虑两个WebPart,其中一个提供串数据,另一个使用整数数据。尽管在这二者之间转换很容易,不过要知道这种技术适用于任何类型,利用简单类型更易于理解转换器的原则。例如,考虑代码清单13-22,它实现了一个WebPartTrasnformer,将一个串提供者的数据转换到一个整数消费者。
代码清单13-22 一个简单的转换器
[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
}
转换器由WebPartTransformer属性标识,它定义了从哪个类型转换以及转换为哪个类型。这个类继承自WebPartTransformer,实现了IIntegerData接口(消费者使用的接口)。可以通过Transform方法访问串数据,IIntegerData接口的实现只是转换这个接口的数据。
使用转换器之前,必须在web.config的webParts transformers元素中先定义。类型必须设置为转换器的完全类型名,如代码清单13-23所示。
代码清单13-23 配置转换器
<webParts enableExport="true">
<transformers>
<add name="String to Integer Transformer"
type="Sample.Web.UI.IntegerToStringTransformer"/>
</transformers>
</webParts>
运行时,转换器介入到WebPart之间的连接中,首先允许连接(因为转换器会转换不兼容的类型),然后完成具体的转换过程。其好处在于,这种技术可以用于从第三方WebPart转换数据,而不必要求第三方以其不需要的形式提供(或使用)数据。你也可以自行编写转换器,来集成以前不兼容的WebPart。











