Web Part Connections in WSS 3.0 (Part 4)


In part 1 of this series, I showed how to make one web part accept data from another.  In part 2, I showed that this can be extended so that one web part can provide data for many.  In part 3, which I thought was going to be the last part, I showed how a single web part can accept data from multiple web parts.  Now, in the fourth part of my three-part series, I'm going to show how data can be passed from one web part to another in a sort of chain.


I have three web parts; NumberPicker, NumberDoubler, and NumberTripler.  I want the data to flow like this:


NumberPicker --> NumberDoubler --> NumberTripler


The user will use NumberPicker to select a number from one to five.  This number is passed to NumberDoubler, which doubles the number and displays it.  This doubled number is then passed to NumberTripler, which triples the number and displays the final result.  The important point here is that data is received from one part and provided to the next, and specifically that the data provided depends upon the data recieved. Here's the code that I used:


INumber
Public Interface INumber


    ReadOnly Property Number() As Integer


End Interface


NumberPicker
Imports System
Imports System.ComponentModel
Imports System.Web.UI.HtmlControls
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts


Public Class NumberPicker
    Inherits WebPart
    Implements INumber


    Private _NumberList As DropDownList


    Public Sub New()


        Me.ExportMode = WebPartExportMode.All


    End Sub


    Protected Overrides Sub CreateChildControls()
        MyBase.CreateChildControls()


        Dim t As Table = Nothing
        Dim tr As TableRow = Nothing
        Dim td As TableCell = Nothing


        Try
            _NumberList = New DropDownList


            With _NumberList
                .AutoPostBack = True


                .Items.Clear()


                .Items.Add(New ListItem("One", 1))
                .Items.Add(New ListItem("Two", 2))
                .Items.Add(New ListItem("Three", 3))
                .Items.Add(New ListItem("Four", 4))
                .Items.Add(New ListItem("Five", 5))


                .SelectedIndex = 0
            End With


            t = New Table
            tr = New TableRow


            td = New TableCell
            td.Text = "Number: "
            tr.Controls.Add(td)


            td = New TableCell
            td.Controls.Add(_NumberList)
            tr.Controls.Add(td)


            t.Controls.Add(tr)


            Me.Controls.Add(t)
        Catch ex As Exception
            Me.Controls.Clear()


            Dim msg As New Literal()
            msg.Text = ex.Message
            Me.Controls.Add(msg)
        End Try


    End Sub


    <ConnectionProvider("Selected Number")> _
    Public Function GetNumberInterface() As INumber
        Return Me
    End Function


    Public ReadOnly Property Number() As Integer Implements INumber.Number
        Get
            Return _NumberList.SelectedValue
        End Get
    End Property


End Class


NumberDoubler
Imports System
Imports System.ComponentModel
Imports System.Web.UI.HtmlControls
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts


Public Class NumberDoubler
    Inherits WebPart
    Implements INumber


    Protected _numberInterface As INumber = Nothing
    Protected _number As Integer = 0
    Protected _result As Integer = 0


    Protected _headerMessage As Literal = Nothing


    Public Sub New()


        Me.ExportMode = WebPartExportMode.All


    End Sub


    Protected Overrides Sub CreateChildControls()
        MyBase.CreateChildControls()


        Try
            _headerMessage = New Literal
            Me.Controls.Add(_headerMessage)
        Catch ex As Exception
            Me.Controls.Clear()


            Dim msg As New Literal()
            msg.Text = ex.Message
            Me.Controls.Add(msg)
        End Try


    End Sub


    Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
        MyBase.OnPreRender(e)


        If _numberInterface IsNot Nothing Then
            _number = _numberInterface.Number
            _result = 2 * _number
        End If


    End Sub


    Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)


        If _headerMessage IsNot Nothing AndAlso _number > 0 Then
            _headerMessage.Text = _result
        End If


        MyBase.RenderContents(writer)


    End Sub


    <ConnectionConsumer("Selected Number", "1")> _
    Public Sub AcceptNumberInterface(ByVal numberInterface As INumber)
        _numberInterface = numberInterface
    End Sub


    <ConnectionProvider("Doubled Number", "2")> _
    Public Function GetNumberInterface() As INumber
        Return Me
    End Function


    Public ReadOnly Property Number() As Integer Implements INumber.Number
        Get
            Return _result
        End Get
    End Property
End Class


NumberTripler
Imports System
Imports System.ComponentModel
Imports System.Web.UI.HtmlControls
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts


Public Class NumberTripler
    Inherits WebPart


    Protected _numberInterface As INumber = Nothing
    Protected _number As Integer = 0
    Protected _result As Integer = 0


    Protected _headerMessage As Literal = Nothing


    Public Sub New()


        Me.ExportMode = WebPartExportMode.All


    End Sub


    Protected Overrides Sub CreateChildControls()
        MyBase.CreateChildControls()


        Try
            _headerMessage = New Literal
            Me.Controls.Add(_headerMessage)
        Catch ex As Exception
            Me.Controls.Clear()


            Dim msg As New Literal()
            msg.Text = ex.Message
            Me.Controls.Add(msg)
        End Try


    End Sub


    Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
        MyBase.OnPreRender(e)


        If _numberInterface IsNot Nothing Then
            _number = _numberInterface.Number
            _result = 3 * _number
        End If


    End Sub


    Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)


        If _headerMessage IsNot Nothing AndAlso _number > 0 Then
            _headerMessage.Text = _result
        End If


        MyBase.RenderContents(writer)


    End Sub


    <ConnectionConsumer("Doubled Number", "3")> _
    Public Sub AcceptNumberInterface(ByVal numberInterface As INumber)
        _numberInterface = numberInterface
    End Sub


End Class


The real trick here is that the numbers are calculated during the OnPreRender event.  We have to wait long enough to ensure that the NumberPicker web part has created its internal controls, which is where the original data resides.  We also need to act early enough to allow the data to be passed along from part to part.  If you are not careful, one of the web parts may be rendered before the data has been passed to it.


I hope this helps.

Comments (2)
  1. Ernie says:

    I think this will only work if you are only usingeb parts that you create.  If you were to use a WSS List instead of the NumberPicker, I believe the doubler would not consume before it provided to the tripler.  I had a situation where I had a chain set up with a WSS List -> Custom Web part -> 3rd party web part.  The Custom web part both consumed from the WSS list and provided to the 3rd part part.  Using the pre render event did not ensure the proper chain of execution.  The solution was to make a direct connection from the custom part to the wss list.  Not ideal but it did ensure the proper execution order.

Comments are closed.

Skip to main content