top
Loading...
引入ASP.NET2.0Web部件連接
當您開始使用 Microsoft .NET Framework 2.0 和 ASP.NET 時,您會發現新的 Web 部件基礎結構將一些非常強大的功能添加到了基礎平臺中。對于本文,我假設您已經對 Web 部件的基本知識有所了解,例如,如何使用 WebPartManager 控件、Web 部件區域、編輯器、目錄和持久性屬性。

創建用于ASP.NET 2.0應用程序的Web部件

您可以用兩種方法創建 Web 部件。第一種方法涉及創建一個自定義的 Web 部件類,該類從 System.Web.UI.WebControls.WebParts 命名空間中定義的 WebPart 類繼承。使用該方法時,將自定義的 Web 部件類打包到一個程序集 DLL 中通常是有意義的,因為這樣可以提供對重用、版本控制和 Visual Studio 2005 集成的更多控制。如果您對使用以前的 ASP.NET 版本生成自定義控件很熟悉,則許多相同的技術適用于將自定義的 Web 部件生成到 DLL 程序集中。

用于創建 ASP.NET 2.0 Web 部件的第二種方法涉及使用用戶控件。雖然該方法不產生相同的重用和版本控制級別,但是它的確允許您使用 Visual Studio 窗體設計器來創建 Web 部件的用戶界面部分。如果您想通過將用于用戶輸入、驗證和數據綁定的控件拖放到設計界面上來創建應用程序,則該方法適合于您。當然,如果您已經花時間創建了一個您想用作 Web 部件的用戶控件,它也是個可以采用的好方法。

當創建一個專門設計為 Web 部件的用戶控件時,建議您實現 IWebPart 接口。這樣,Web 部件后臺的代碼就可通過編程方式分配自己的幾個內部 Web 部件屬性,如它的 Title 和 TitleIconUrl。

本文附帶的代碼示例使用一個名為 WebPartBase 的自定義基類,該基類從 UserControl 繼承并實現 IwebPart。該基類的定義部署在 App_Code 目錄中名為 WebPartBase.vb 的源文件中。每當您使用用戶控件創建一個新 Web 部件時,只需在該代碼隱藏文件中更改該基類以利用該技術:

Partial Class WebParts_Customers         Inherits WebPartBase   Sub New()     Title = "Northwind Customer List"     TitleIconImageUrl = "'imgCustomers.gif"   End Sub End Class 

設計可連接的 Web 部件

使用 Web 部件連接,您可以使用戶更輕松地形象化數據各項之間存在的關系。例如,Web 部件連接可以建模一個主-從方案,其中顯示客戶列表的 Web 部件連接到另一個顯示當前所選客戶詳細信息的 Web 部件。圖 1 的示例說明這種設計可能生成的用戶界面外觀。



圖 1

Web 部件連接還可用于建模一對多關系。例如,顯示客戶列表的 Web 部件可以連接到另一個顯示針對當前所選客戶的所有定單的 Web 部件。

通常使用 Web 部件連接建模的另一個方案是表單查詢。在這種方案中,一個 Web 部件提供一個用戶界面,該用戶界面允許用戶選擇查詢數據(如數據庫表)時所用的搜索或篩選條件。然后,該 Web 部件連接到另一個顯示查詢結果的 Web 部件。Web 部件連接用于在運行查詢前,將篩選條件從一個 Web 部件傳遞到另一個 Web 部件。

Web 部件連接基于提供者和使用者的概念。提供者 Web 部件通過一個編程接口為一個或多個使用者 Web 部件提供信息。提供者和使用者之間交換的信息可以是簡單的數據項(如數字或字符串),也可以是較特殊的內容(如對一個復雜數組或自定義對象集合的引用)。

如果針對 Windows SharePoint Services 2.0 (WSS) 編寫了 Web 部件,您可能已經熟悉它用于連接 Web 部件的模型。在 WSS 中,Web 部件只能使用一組預定義的接口對連接。這些接口對的示例包括 ICellProvider 和 ICellConsumer,以及 IRowProvider 和 IRowConsumer。

ASP.NET 2.0 中的 Web 部件連接模型比 WSS 中的舊式模型更容易、更靈活,因為您可以使用自己的自定義接口。這意味著您無需使用由 Microsoft 人員創建的接口定義。而且,您無需對接口對進行任何操作,它們必須由提供者和使用者實現。使用 ASP.NET 2.0,只有提供者需要實現一個接口。

要了解其工作方式,我們先在兩個 Web 部件之間創建一個連接。對于我要在本月專欄中提供的示例,我決定使用 Northwind 數據庫,因為它有一個 Customers 表和一個 Orders 表。這使我能為您展示如何針對主-從和一對多關系設計 Web 部件。有一點需要注意,如果使用 SQL Server 2005,則在產品安裝過程中并不安裝該示例 Northwind 數據庫。要安裝它,您必須下載并運行 Microsoft Web 站點上可用的腳本。

現在,假設您要在一個顯示客戶列表的 Web 部件和一個顯示當前所選客戶的詳細信息的客戶 Web 部件之間建立一個 Web 部件連接,如圖 1所示。顯示客戶列表的 Web 部件將扮演提供者的角色,而顯示當前所選客戶的詳細信息的 Web 部件則作為使用者。在這種情況下,您希望提供者為使用者提供當前所選客戶的 CustomerID 字段。

首先,創建一個名為 ICustomerIDProvider 的簡單接口:

Public Interface ICustomerIDProvider     ReadOnly Property CustomerID() As String End Interface 

在本文的代碼示例中,我使用帶有 SqlDataSource 和 GridView 控件的用戶控件創建了提供者 Web 部件,以顯示來自 Northwind 的客戶。Web 部件源文件是 Customers.ascx 和 Customers.ascx.vb,如圖 2 所示。

 Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts

Partial Class WebParts_Customers
        Inherits WebPartBase
        Implements ICustomerIDProvider

    Sub New()
        Title = "NorthWind Customer List"
        TitleIconImageUrl = "'imgCustomers.gif"
    End Sub

    <ConnectionProvider("Customer ID Provider")> _
    Public Function GetCustomerProvider() As ICustomerIDProvider
        Return Me
    End Function

    Public ReadOnly Property CustomerID() As String _
            Implements ICustomerIDProvider.CustomerID
        Get
            If gridCustomers.SelectedDataKey Is Nothing Then
                 Return String.Empty
            Else
                 Return Me.gridCustomers.SelectedDataKey.Value
            End If
        End Get
    End Property
End Class

您可以看到,WebParts_Customers 作為提供者并實現用于該 Web 部件連接的接口。在本例中,WebParts_Customers 實現 ICustomerIDProvider 接口。雖然最常見的模式是提供者本身實現該連接接口,但是它不需要這么做。唯一的實際要求是,ConnectionProvider 方法返回指定接口的一個實例。因此,作為替代方案,該提供者 Web 部件可以返回一個實現該連接接口的 helper 對象。如果一個提供者 Web 部件具有多個接口類型相同的連接點,這通常是有必要的。

通過返回 GridView 控件的 SelectedDataKey 屬性的值,WebParts_Customers 類實現 CustomerID 屬性。GridView 控件已經進行了設置以便顯示來自 Northwind Customers 表的記錄,而且它還將 CustomerID 字段識別為 SelectedDataKey 值。

您應該注意到 WebParts_Customers 類有一個名為 GetCustomerProvider 的方法,該方法具有一個根據 ICustomerIDProvider 接口定義的返回類型。在這種情況下,由于 Web 部件本身實現所需的接口,因此 GetCustomerProvider 可以只返回對該類的當前實例的 Me 引用。您還要注意該方法已經使用 ConnectionProvider 屬性進行了定義:
<ConnectionProvider("Customer ID Provider")> 

WebPartManager 負責在運行時連接 Web 部件。當 WebPartManager 看到一個 Web 部件包含一個使用 ConnectionProvider 屬性定義的方法時,它知道該 Web 部件公開一個連接點,因此可以作為提供者并且連接到使用者。當需要將兩個 Web 部件連接在一起時,WebPartManager 將調用 GetCustomerProvider 方法獲取對提供者 Web 部件的強類型引用。

定義一個提供者 Web 部件是否接受到使用者的多個連接是可能的。在某種情況下,一個提供者同時具有到多個使用者的連接是很有用的。在其他情況下,您可能想限制提供者,使它最多可以有一個到使用者 Web 部件的連接。默認情況下,提供者允許多個連接,而使用者則不然。要改變這一點,當您應用 ConnectionProvider 屬性時,可以使用命名參數 AllowsMultipleConnections,如下所示:

<ConnectionProvider("Customer ID Provider", _     AllowsMultipleConnections:=False)> 

既然您已經看到如何創建一個在提供者 Web 部件中公開連接點的方法,我們來看看這在使用者 Web 部件中是如何實現的。使用者 WebPart 通過提供一個使用 ConnectionConsumer 屬性定義的方法來公開連接點。使用者的連接點方法與提供者的連接方法不同,因為它不定義返回值。相反,它獲取一個用該連接的接口類型定義的參數:

<ConnectionConsumer("Customer ID Consumer")>  _ Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)     ... ' implementation End Sub 

請記住,提供者的連接點方法名稱與使用者的連接點方法名稱并不重要。唯一需要注意的是,每個方法分別使用 ConnectionProvider 屬性和 ConnectionConsumer 屬性進行定義。

現在,我們看看 WebPartManager 在運行時是如何建立該連接的。WebPartManager 調用提供者的連接點方法以獲取對提供者對象的引用。接下來,WebPartManager 調用使用者的連接點方法,以便為它傳遞一個對提供者的強類型引用。

一旦WebPartManager 完成它的工作之后,使用者 Web 部件就有一個返回到提供者 Web 部件的活動連接。此時,使用者可以使用該引用訪問接口中定義的方法和屬性,從而與提供者直接交互。但是,ASP.NET 小組建議使用者 Web 部件在 PreRender 階段之前不應使用提供者接口上的方法和屬性。具體說來,它們不應該在 方法本身中使用提供者接口上的方法和屬性。原因是這些連接可能彼此依賴。您可能有一個連接到 ProviderConsumerWebPart 進而連接到 ConsumerWebPart 的 ProviderWebPart。在這兩個連接建立之前,ConsumerWebPart 無法查詢提供者接口,而且連接建立的順序取決于框架。

圖 3 顯示 CustomerDetails.ascx.vb 中使用者 Web 部件的完整代碼列表。您可以看到,使用者 Web 部件負責持續引用,以便可以跟蹤到提供者的連接。該使用者 Web 部件包含一個名為 provider 的私有字段,該字段是根據 ICustomerIDProvider 接口定義的。

 Partial Class WebParts_CustomerDetails
        Inherits WebPartBase

    Sub New()
        Me.Title = "Customer Details"
        Me.TitleIconImageUrl = "'imgCustomer.gif"
    End Sub

    Private provider As ICustomerIDProvider

    <ConnectionConsumer("Customer ID Consumer")> _
    Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
        Me.provider = provider
    End Sub

    Protected Sub SqlDataSource1_Selecting(ByVal sender As Object, _
            ByVal e As SqlDataSourceSelectingEventArgs) _
            Handles SqlDataSource1.Selecting
        SqlDataSource1.FilterExpression = _
            "CustomerID='" & provider.CustomerID & "'"
    End Sub

End Class

當 WebPartManager 調用 RegisterCustomerProvider 時,使用者獲取傳入的引用參數并將它分配給提供者字段。當提供者字段分得該引用后,使用者 Web 部件就可以與提供者 Web 部件直接交互。為連接設計該接口時,您應該添加將提供您所需交互的任何方法和屬性。

在某些情況下,使用者 Web 部件可能設計為無論是否有到提供者的活動連接都正常工作。在這種設計中,當提供者字段有一個 Nothing 值時,您可能希望將臨時代碼添加到正常工作的使用者 Web 部件中:

If provider IsNot Nothing Then     ... ' interact with provider Else     ... ' contingency code goes here if required End If 

為一個 Web 部件連接計時

當您開始設計支持連接的 Web 部件時,了解所涉及的計時是非常重要的。圖 4 顯示在 HTTP GET 期間運行提供者 Web 部件和使用者 Web 部件的頁面的一小部分。雖然有更多在 HTTP POST 期間激發的頁面級事件,但是連接建立時的計時則保持相同。



圖 4

圖 4 中顯示的跟蹤信息闡釋了對于標準的 ASP.NET 2.0 頁面級事件而言,每個連接方法何時激發。您應該能夠從該跟蹤信息中看到,WebPartManager 在頁面級 LoadComplete 命令中將 Web 部件連接在一起。

需要牢記的是,當頁面級事件 PreInit、Init、PreLoad 和 Load 執行時,Web 部件連接尚未建立。這意味著您絕不應該嘗試訪問使用者 Web 部件的處理程序方法(它綁定到這些事件之一)中的提供者。在嘗試訪問提供者 Web 部件之前,使用者 Web 部件中的代碼必須等待 LoadComplete 事件執行完畢。

在本示例中,使用者 Web 部件處理 SqlDataSource 控件的 Selecting 事件,該事件在頁面級 PreRender 事件中激發。此時,訪問提供者并檢索客戶 ID 是安全的。

定義靜態 Web 部件連接

既然您已經看到如何創建支持連接的 Web 部件,并且了解了所涉及的計時,現在該探究如何將它們實際連接在一起了。您將看到,可以將標記直接添加到一個 Web 部件頁面定義中,以便建立一個靜態 Web 部件連接。也可以在運行時通過代碼或用戶交互動態建立 Web 部件連接。首先,我要展示如何在兩個 Web 部件之間創建一個靜態連接,因為這是最簡單的方法。

要在一個頁面上的兩個 Web 部件之間創建靜態 Web 部件連接,需要將 StaticConnections 元素添加到 WebPartManager 標記中:

<asp:WebPartManager ID="WebPartManager1" runat="server">     <StaticConnections>         <asp:WebPartConnection ID="c1"              ProviderID="Customers1"             ConsumerID="CustomerDetails1" />     </StaticConnections> </asp:WebPartManager> 

要使該代碼正常運行,名為 Customers1 的提供者 Web 部件和名為 CustomerDetails1 的使用者 Web 部件也必須在同一頁面上的 Web 部件區域中靜態定義和正確命名。

需要牢記的是,每個頁面只有一個 WebPartManager 控件。然而,在許多涉及 Web 部件的應用程序設計中,您會發現將 WebPartManager 添加到用戶控件或母版頁很方便,原因是可以在許多頁面上重用它。

當 Web 部件頁面基于母版頁,或者使用的是包含 WebPartManager 控件的用戶控件時,您不能添加 WebPartManager 控件的第二個示例來定義 StaticConnections 標記。針對這些情況,ASP.NET 2.0 Web 部件控件集提供了 ProxyWebPartManager 控件。以下是關于如何使用它的示例:

<asp:ProxyWebPartManager ID="ProxyWebPartManager1" runat="server">     <StaticConnections>         <asp:WebPartConnection ID="c1"              ProviderID="Customers1"              ConsumerID="CustomerDetails1" />     </StaticConnections> </asp:ProxyWebPartManager> 

ProxyWebPartManager 控件的價值在于,它允許您在頁面無法包含 WebPartManager 標記時,在頁面級添加靜態連接。在本專欄附帶的示例頁面 default.aspx 中,必須使用 ProxyWebPartManager 建立一個靜態 Web 部件連接,原因是 WebPartManager 已經封裝在名為 WebPartManagerPanel.ascx 的用戶控件中。

命名連接點

在我目前生成的示例中,提供者 Web 部件和使用者 Web 部件之間的連接已經基于默認的連接點。但是,Web 部件連接方法提供一個命名連接點是可能的。要將一個命名連接點添加到提供者,您只需將第二個字符串參數添加到 ConnectionProvider 屬性:

<ConnectionProvider("Customer ID Provider", "CustomerIDProvider")> _ Public Function GetCustomerProvider() As ICustomerIDProvider     Return Me End Function 

之所以使用命名連接點的一個原因是提供者或使用者可能有多個連接點,因此必須能區分它們。要將一個命名連接點添加到使用者 Web 部件,您可以將第二個字符串參數添加到 ConnectionConsumer 屬性:

<ConnectionConsumer("Customer ID" & "Consumer", "CustomerIDConsumer")> _ Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)     Me.provider = provider End Sub 

當您開始使用命名連接點時,在頁面級定義 StaticConnections 標記時,必須為 ProviderConnectionPointID 和 ConsumerConnectionPointID 提供兩個額外的屬性值。

動態建立連接

當您想將 Web 部件連接在一起時,有時卻無法依賴靜態 Web 部件連接。例如,如果您想連接通過自定義代碼動態創建的 Web 部件,或者由使用 Web 部件目錄將 Web 部件添加到頁面的用戶動態創建的 Web 部件,就會出現這種情況。

在無法使用靜態 Web 部件連接時,您必須使用動態技術連接 Web 部件。為此,可以使用自定義代碼,或者使用 ASP.NET 2.0 Web 部件控件集附帶的 ConnectionsZone 控件。

讓我們首先看一下創建兩個 Web 部件并將它們動態連接在一起的自定義代碼,如圖 5 所示。該代碼通過用戶控件為提供者和使用者創建了 Web 部件實例,并將它們添加到宿主 Web 部件頁面的現有 Web 部件區域。然后,該代碼在它們之間建立一個連接。請注意,Web 部件和連接將保存為用戶個性化信息的一部分,因此它們應該只添加到 WebPartManager 一次。如果您不想以這種方式保存 Web 部件和連接,也可以使用其他 API。

'*** get WebPartManager object
Dim wpMgr As WebPartManager = _
    WebPartManager.GetCurrentWebPartManager(Me.Page)

'*** create and add provider Web Part
Dim uc1 As UserControl = Me.Page.LoadControl("'WebPartsCustomers.ascx")
uc1.ID = "wp1"
Dim wp1 As GenericWebPart = wpMgr.CreateWebPart(uc1)
wp1 = wpMgr.AddWebPart(wp1, LeftWebPartZone, 0)

'*** create and add consumer Web Part
Dim uc2 As UserControl = _
    Me.Page.LoadControl("'WebPartsCustomerDetails.ascx")
uc2.ID = "wp2"
Dim wp2 As GenericWebPart = wpMgr.CreateWebPart(uc2)
wp2 = wpMgr.AddWebPart(wp2, RightWebPartZone, 0)

'*** get desired connection points for provider and consumer
Dim cp1 As ProviderConnectionPoint = _
  wpMgr.GetProviderConnectionPoints(wp1)("CustomerIDProvider")
Dim cp2 As ConsumerConnectionPoint = _
  wpMgr.GetConsumerConnectionPoints(wp2)("CustomerIDConsumer")

'*** dynamically establish Web Part connection
wpMgr.ConnectWebParts(wp1, cp1, wp2, cp2)

圖 5


圖 6 連接顯示模式


您可以看到,圖 5 中顯示的技術需要使用 ProviderConnectionPoint 對象和 ConsumerConnectionPoint。通過調用 WebPartManager 提供的方法并傳遞那些命名連接點的字符串標識符,可以檢索這些對象。

您和您的用戶可以用來建立動態 Web 部件連接的另一種技術涉及到 ConnectionsZone 控件。要有效地使用該技術,您應該創建一個 Web 部件頁面,其右側有一個包含 ConnectionsZone 控件的任務窗格。當用戶使該頁面處于連接視圖顯示模式中時,Connect 命令將添加到公開連接點的每個 Web 部件的 Web 部件菜單中,如圖 6 所示。

當用戶選擇 Connect 命令時,Web 部件頁面會顯示 ConnectionsZone 控件,并允許用戶查看該頁面上所有可連接的 Web 部件的所有兼容連接點(請參見圖 7)。使用該技術,您可以將使用者連接到提供者。同樣,您也可以將提供者連接到使用者。



圖 7

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗