SharePoint 多连接点解决方案

在开发SharePoint项目时,经常会遇到需要一个消费者WebPart连接到多个提供者WebPart的场景。然而,ASP.NET / WSS 3.0 / MOSS 2007默认只允许一对一的连接。本文将介绍一种解决方案,使得这种多对一的连接成为可能。

几周前,在开发一个SharePoint项目时遇到了一个难题。需求是当点击列表项时,需要在列表右侧显示一些帮助/信息文本。同时,一个门户页面上可以有多个列表,且相同的帮助/信息文本WebPart需要被复用。本以为这很容易实现,因为知道ConnectedConsumerAttribute类有一个AllowMultipleConnection属性,只需要将其设置为true即可。但事实证明错了。在查阅了众多论坛、博客、维基后,发现许多人都遇到了和一样的问题。遗憾的是,未能找到问题的解决方案,这促使提出了一个潜在的解决方案(虽然在此过程中也想出了其他几种方案,但认为这是最优雅的)

这不是一个使用VS 2008开发代码的分步教程;假设已经知道如何操作。将使用代码描述解决方案的概念。开发环境如下:

  • Vista Enterprise
  • VSTS 2008
  • WSS 3.0(使用Bamboo Solutions安装在Vista上)
  • VS Extensions forSharePointSVCS 1.2

请注意,如果是在Vista上使用,请以提升的权限启动VS,并不要忘记在项目调试属性中更改WSS URL。

首先,创建了一个名为ConnectedConsumerInterfaceAttribute的自定义属性类,用于标记消费者WebPart上的相关方法。这个方法将由提供者WebPart调用。

public class ConnectConsumerInterfaceAttribute : Attribute { private Type _interfaceType; public ConnectConsumerInterfaceAttribute(Type interfaceType) { _interfaceType = interfaceType; } public Type InterfaceType { get { return _interfaceType; } } }

接下来,扩展了ASP.NET的WebPart类,创建了一个名为ProviderWebPart的类。所有需要连接到多连接消费者的提供者都需要继承这个新类。添加了一个名为InvokeConnectedConsumer的受保护虚拟方法,其签名如下:

protected virtual void InvokeConnectedConsumer<TInterfaceType>(TInterfaceType graph) { // Retrieve all the consumer web parts using the SPSHelper class... WebPart[] consumerWebParts = SPSHelper.GetConnectedConsumerWebParts( this.WebPartManager, this, typeof(TInterfaceType)); // Process all the consumer web parts... foreach (WebPart consumerWebPart in consumerWebParts) { // Retrieve all the methods of the consumer web part... MethodInfo[] methods = consumerWebParts.GetType().GetMethods( BindingFlags.Public | BindingFlags.Instance); // Loop through each method and check if any // are marked with ConnectConsumerInterfaceAttribute... foreach (MethodInfo method in methods) { // Retrieve all the custom attributes of the method... object[] attributes = method.GetCustomAttributes( typeof(ConnectConsumerInterfaceAttribute), false); // Loop through until we find a valid ConnectConsumerInterfaceAttribute // - there should only be 1... foreach (ConnectConsumerInterfaceAttribute attribute in attributes) { // Check if the interface types are the same... if (typeof(TInterfaceType) == attribute.InterfaceType) { // Now invoke the method pass in the data... method.Invoke(consumerWebPart, new object[] { graph }); // Now need to loop through the rest... break; } } } } }

然后,开发了两个WebPart,分别命名为InputWebPart(提供者)和DisplayWebPart(消费者)。

public class InputWebPart : ProviderWebPart { private TextBox _txtInputText; private ITextData _textData; public InputWebPart() { } protected ITextData TextData { get { if (_textData == null) { _textData = new TextDataProvider(); } return _textData; } set { _textData = value; } } protected override void CreateChildControls() { base.CreateChildControls(); // Add a new text box... _txtInputText = new TextBox(); this.Controls.Add(_txtInputText); // Add a new button... Button btnSend = new Button(); btnSend.Text = "Send"; // Wire up the click event... btnSend.Click += new EventHandler(btnSend_Click); this.Controls.Add(btnSend); } private void btnSend_Click(object sender, EventArgs e) { // this is required to take care of the normal SharePoint behaviour... this.TextData.Text = _txtInputText.Text; // this is where all the magic happens... this.InvokeConnectedConsumer<ITextData>(this.TextData); } // This is required for SharePoint to allow provider to connect to consumers... [ConnectionProvider("Text Data")] public ITextData SetTextData() { return _textData; } } public class DisplayWebPart : System.Web.UI.WebControls.WebParts.WebPart { private ITextData _textData; public DisplayWebPart() { } protected ITextData TextData { get { return _textData; } set { _textData = value; } } protected override void CreateChildControls() { base.CreateChildControls(); if (this.TextData != null) { Label lblDisplayText = new Label(); lblDisplayText.Text = this.TextData.Text; this.Controls.Add(lblDisplayText); } } // Required for SharePoint to allow multiple connections... [ConnectionConsumer("Text Data Consumer", AllowsMultipleConnections = true)] // Required for the provider to invoke multiple connected consumers... [ConnectConsumerInterface(typeof(ITextData))] public void GetTextData(ITextData textData) { this.TextData = textData; this.EnsureChildControls(); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485