Sunday, July 12, 2009

How to create connected web parts: Part 2

Here in Part 2, you will find my tutorial on how to create Contact List/Email Contact connected web parts, along with entire code to be copy and pasted. I recommend following the tutorial, the at the end I will describe what's happening with respect to the transfer of a selected person from one web part to the other.

At a high level:

In the following project, we will create two web parts, a web part called Contact List that will display data from a custom list also called Contact List; and another web part called Email Contact, which will 1. save the message a user types into its form to a custom list called Sent Emails, then 2. email that message to the selected contact person. When a user clicks a contact in the Contact List web part, the person will then appear at the top of the Email Contact web part above the form the user can enter a message into. This transfer of a selected person from the Contact List web part to the Email Contact web part is what requires the web parts to be connected web parts. This connected web part setup also allows us the flexibility of displaying the Contact List by itself, or pairing it with other consumer web parts we develop down the road.

In summary:
  1. Contact List web part requires a custom list called Contact List. Contact List web part will be the provider web part, providing a person to a consumer web part, in this example it will be the Email Contact web part.
  2. Email Contact web part requires a custom list called Sent Emails. Email Contact web part will be the consumer, consuming a person from a provider web part, in this example it will be the Contact List web part.
  3. The two web parts will both use the same interface, we'll call it IContact.
  4. Once both web parts are built and deployed, they can then be individually added to a page on your SharePoint site, then you will connect them by clicking either web part -> Modify Shared Web Part -> Connections
Ok, so that was the all the high-level stuff. Let's do this step by step from the beginning. All you have to do is click along and paste code.

I. First, the easy part - we have to create the two custom lists Contact List
and Sent Emails in your SharePoint site.
  1. In your SharePoint site, click Site Actions -> Create -> Custom List
  2. for Name, type Contact List
  3. click Create
  4. click Contact List in the left menu
  5. click Settings -> List Settings
  6. click Title column, rename to Contact Name, click OK
  7. click Create Column, for Column name type Job Title, click OK
  8. click Create Column, for Column name type Email Address, click OK
  9. click Create Column, for Column name type Phone, click OK
  10. click Create Column, for Column name type Fax, click OK
  11. Now that you have created the contact list, enter in 2 or 3 contacts by clicking Contact List, then New -> New Item, then fill out ALL the fields (including the phone and fax) and click OK (I still need to add error handling on the web part if a value is empty)
  12. In your SharePoint site, click Site Actions -> Create -> Custom List
  13. for Name, type Sent Emails
  14. click Create
  15. click Sent Emails in the left menu
  16. click Settings -> List Settings
  17. click Title column, and rename to Message Subject, click OK
  18. click Create Column, for Column name type Submitter Name, click OK
  19. click Create Column, for Column name type Submitter Email, click OK
  20. click Create Column, for Column name type Message, click OK
  21. click Create Column, for Column name type Contact Email, click OK

II. Now, we create the interface and web parts in Visual Studio 2008.
  1. load Visual Studio 2008
  2. File -> New -> Project -> Visual Basic -> SharePoint -> Web Part
  3. for Name and Solution Name, type: ContactUs
  4. Click OK
  5. In Solution Explorer, right-click the project name ContactUs, then click Properties
  6. Click the Debug tab and in "Start browser with URL:", type the SharePoint site you want these web parts to be deployed to
  7. Click X to close out of Properties
  8. In Solution Explorer, right-click WebPart1 and click Delete, then OK
  9. In Solution Explorer, right-click project ContactUs, then click Add -> New Item -> SharePoint -> Web Part and for the name type ContactList, then click Add
  10. In Solution Explorer, right-click project ContactUs, then click Add -> New Item -> SharePoint -> Web Part and for the name type ContactList, then click Add
  11. In Solution Explorer, right-click project ContactUs, then click Add -> New Item -> Code -> Interface and for the name type IContact.vb, then click Add
  12. In IContact.vb, copy and paste the following code:

    Property ContactName() As String
    Property JobTitle() As String
    Property EmailAddress() As String
    Property Phone() As String
    Property Fax() As String

  13. In Solution Explorer, right-click References, then click Add Reference; in the .NET tab, select System.Drawing and click OK
  14. In ContactList.vb, comment out the first two lines, Option Explicit On and Option Strict On
  15. In ContactList.vb, add the following code directly below Public Class ContactList (delete the other pre-generated code within the class):

    Inherits System.Web.UI.WebControls.WebParts.WebPart
    Implements IContact

    WithEvents oContactNameLink As LinkButton
    Private ContactNameToEmail As String = String.Empty
    Private JobTitleToEmail As String = String.Empty
    Private EmailAddressToEmail As String = String.Empty
    Private PhoneToEmail As String = String.Empty
    Private FaxToEmail As String = String.Empty


    Dim strContactListDataSource As String = ""

    <WebBrowsable(True), Personalizable(True), FriendlyName("Contact List Data Source"), SPWebCategoryName("Data")> _
    Property ContactListDataSource() As String
    Get
    Return strContactListDataSource
    End Get
    Set(ByVal value As String)
    strContactListDataSource = value
    End Set
    End Property


    Public Sub New()
    End Sub


    <Personalizable()> _
    Public Property ContactName() As String _
    Implements IContact.ContactName

    Get
    Return ContactNameToEmail
    End Get
    Set(ByVal value As String)
    ContactNameToEmail = value
    End Set
    End Property


    <Personalizable()> _
    Public Property JobTitle() As String _
    Implements IContact.JobTitle

    Get
    Return JobTitleToEmail
    End Get
    Set(ByVal value As String)
    JobTitleToEmail = value
    End Set
    End Property


    <Personalizable()> _
    Public Property EmailAddress() As String _
    Implements IContact.EmailAddress

    Get
    Return EmailAddressToEmail
    End Get
    Set(ByVal value As String)
    EmailAddressToEmail = value
    End Set
    End Property


    <Personalizable()> _
    Public Property Phone() As String _
    Implements IContact.Phone

    Get
    Return PhoneToEmail
    End Get
    Set(ByVal value As String)
    PhoneToEmail = value
    End Set
    End Property


    <Personalizable()> _
    Public Property Fax() As String _
    Implements IContact.Fax

    Get
    Return FaxToEmail
    End Get
    Set(ByVal value As String)
    FaxToEmail = value
    End Set
    End Property



    ' This is the callback method that returns the provider.
    <ConnectionProvider("Contact Provider", "ContactProvider")> _
    Public Function ProvideIContact() As IContact
    Return Me
    End Function


    Protected Overrides Sub CreateChildControls()
    MyBase.CreateChildControls()


    'if ContactListSource is a valid list, display controls
    If ContactListIsValid() Then

    Try
    'get the site the web part is running on
    Dim oWeb As SPWeb
    oWeb = Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(Context)

    'get the list we are going to work with
    Dim oList As SPList
    oList = oWeb.Lists(ContactListDataSource)


    'create table object
    Dim oTable As New Table
    'oTable.Width = 100
    oTable.CellPadding = 0
    oTable.CellSpacing = 0


    'add the table row
    Dim oRow As New TableRow
    oTable.Rows.Add(oRow)


    'add the cells
    Dim oCellHeaderName As New TableCell
    oCellHeaderName.Width = 180
    oCellHeaderName.Text = "Name"
    oRow.Cells.Add(oCellHeaderName)

    Dim oCellHeaderJobTitle As New TableCell
    oCellHeaderJobTitle.Width = 180
    oCellHeaderJobTitle.Text = "Job Title"
    oRow.Cells.Add(oCellHeaderJobTitle)

    Dim oCellHeaderEmail As New TableCell
    oCellHeaderEmail.Width = 180
    oCellHeaderEmail.Text = "Email Address"
    oRow.Cells.Add(oCellHeaderEmail)

    Dim oCellHeaderPhone As New TableCell
    oCellHeaderPhone.Width = 100
    oCellHeaderPhone.Text = "Phone"
    oRow.Cells.Add(oCellHeaderPhone)

    Dim oCellHeaderFax As New TableCell
    oCellHeaderFax.Width = 100
    oCellHeaderFax.Text = "Fax"
    oRow.Cells.Add(oCellHeaderFax)


    'for all rows in list, display them
    For Each oContactListItem As SPListItem In oList.Items
    'add the table row for the new list item
    Dim oContactRow As New TableRow
    oTable.Rows.Add(oContactRow)


    Dim strPhone As String = ""
    If Not oContactListItem.Item("Phone") Is Nothing Then
    strPhone = oContactListItem.Item("Phone").ToString
    End If

    Dim strFax As String = ""
    If Not oContactListItem.Item("Phone") Is Nothing Then
    strFax = oContactListItem.Item("Fax").ToString
    End If



    'add the cells
    Dim oCellName As New TableCell
    oContactNameLink = New LinkButton
    oContactNameLink.Text = oContactListItem.Item("Contact Name").ToString
    oContactNameLink.CommandArgument = oContactListItem.Item("Job Title").ToString & "|" & _
    oContactListItem.Item("Email Address").ToString & "|" & _
    strPhone & "|" & _
    strFax & "|"
    AddHandler oContactNameLink.Click, AddressOf ContactSelected
    oCellName.Controls.Add(oContactNameLink)
    oContactRow.Cells.Add(oCellName)


    Dim oCellJobTitle As New TableCell
    oCellJobTitle.Text = oContactListItem.Item("Job Title").ToString
    oContactRow.Cells.Add(oCellJobTitle)

    Dim oCellEmailAddress As New TableCell
    oCellEmailAddress.Text = oContactListItem.Item("Email Address").ToString
    oContactRow.Cells.Add(oCellEmailAddress)

    Dim oCellPhone As New TableCell
    If Not oContactListItem.Item("Phone") Is Nothing Then
    oCellPhone.Text = oContactListItem.Item("Phone").ToString
    Else
    oCellPhone.Text = ""
    End If
    oContactRow.Cells.Add(oCellPhone)

    Dim oCellFax As New TableCell
    If Not oContactListItem.Item("Fax") Is Nothing Then
    oCellFax.Text = oContactListItem.Item("Fax").ToString
    Else
    oCellFax.Text = ""
    End If

    oContactRow.Cells.Add(oCellFax)

    Next

    'add the table to the web part controls collection
    Controls.Add(oTable)

    Catch ex As Exception
    Dim lblErrorMessage As New Label
    lblErrorMessage.ForeColor = Drawing.Color.Red
    lblErrorMessage.Text = "Error: " & ex.Message & _
    "<BR><BR>" & "Details: " & ex.ToString
    Controls.Add(lblErrorMessage)

    End Try

    Else
    'else display message telling user they must configure the ContactListDataSource property
    Dim lblConfigureMessage As New Label
    lblConfigureMessage.ForeColor = Drawing.Color.Red
    lblConfigureMessage.Text = "<BR><BR>" & "You must configure the Contact List Data Source property. " & _
    "<BR><BR>" & "Please click Modify Shared Web Part -> Data -> Contact List Data Source " & _
    "and set it to a list based on the ContactListTemplate list template."
    Controls.Add(lblConfigureMessage)
    End If

    End Sub


    Private Sub ContactSelected(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles oContactNameLink.Click
    'when a contact is selected, assign their info to local variables

    Dim ContactFields As String
    Dim ContactFieldsArray(4) As String

    'assign person's name to local variable ContactNameToEmail
    ContactNameToEmail = CType(sender, LinkButton).Text

    'pull contact fields from button's CommandArgument property
    ContactFields = CType(sender, LinkButton).CommandArgument

    'split contact fields into an array
    ContactFieldsArray = ContactFields.Split("|")

    'assign contact fields to local variables
    JobTitleToEmail = ContactFieldsArray(0)
    EmailAddressToEmail = ContactFieldsArray(1)
    PhoneToEmail = ContactFieldsArray(2)
    FaxToEmail = ContactFieldsArray(3)

    End Sub


    Private Function ContactListIsValid() As Boolean
    'PURPOSE: returns true if specified contact list is valid for the web part

    Try
    'get the site the web part is running on
    Dim oWeb As SPWeb
    oWeb = Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(Context)

    'get the list specified by user in property, if list is not found in site, flow will hit Catch
    Dim oList As SPList
    oList = oWeb.Lists(ContactListDataSource)


    'check if fields exist in list

    Dim blnContactNameFound As Boolean = False
    Dim blnJobTitleFound As Boolean = False
    Dim blnEmailAddressFound As Boolean = False
    Dim blnPhoneFound As Boolean = False
    Dim blnFaxFound As Boolean = False

    'loop through the fields in the list and check to see if all the required fields are in the list
    For Each oField As SPField In oList.Fields
    If Not oField.Hidden And Not oField.ReadOnlyField And oField.Type <> SPFieldType.Attachments Then

    If oField.Title = "Contact Name" Then
    blnContactNameFound = True
    End If

    If oField.Title = "Job Title" Then
    blnJobTitleFound = True
    End If

    If oField.Title = "Email Address" Then
    blnEmailAddressFound = True
    End If

    If oField.Title = "Phone" Then
    blnPhoneFound = True
    End If

    If oField.Title = "Fax" Then
    blnFaxFound = True
    End If

    End If
    Next

    'if all fields were found, return true
    If blnContactNameFound And blnJobTitleFound And blnEmailAddressFound And blnPhoneFound And blnFaxFound Then
    Return True
    Else
    Return False
    End If

    Catch ex As Exception
    Return False

    End Try

    End Function

  16. In EmailContact.vb, add the following code below the Imports statements at the top of the file:

    Imports System.Net.Mail

  17. In EmailContact.vb, add the following code below Public Class EmailContact (delete the other pre-generated code within the class):

    Inherits System.Web.UI.WebControls.WebParts.WebPart

    Private _provider As IContact
    Private _contactName As String
    Private _jobTitle As String
    Private _emailAddress As String
    Private _phone As String
    Private _fax As String

    Private lblContactNameValue As Label
    Private lblJobTitleValue As Label
    Private lblEmailAddressValue As Label
    Private lblPhoneValue As Label
    Private lblFaxValue As Label

    Dim oMessageSubject As TextBox
    Dim oSubmitterName As TextBox
    Dim oSubmitterEmail As TextBox
    Dim oMessage As TextBox

    Dim lblStatusMessage As New Label

    WithEvents btnSave As New Button


    Dim strEmailContactDestination As String = ""

    <WebBrowsable(True), Personalizable(True), FriendlyName("Email Contact Destination"), SPWebCategoryName("Data")> _
    Property EmailContactDestination() As String
    Get
    Return strEmailContactDestination
    End Get
    Set(ByVal value As String)
    strEmailContactDestination = value
    End Set
    End Property


    Dim strSMTPMailHost As String = ""

    <WebBrowsable(True), Personalizable(True), FriendlyName("SMTP Mail Host"), SPWebCategoryName("Data")> _
    Property SMTPMailHost() As String
    Get
    Return strSMTPMailHost
    End Get
    Set(ByVal value As String)
    strSMTPMailHost = value
    End Set
    End Property


    'Public Sub New()
    'End Sub


    ' This method is identified by the ConnectionConsumer
    ' attribute, and is the mechanism for connecting with
    ' the provider.
    <ConnectionConsumer("Contact Consumer", "ContactConsumer")> _
    Public Sub GetIContact(ByVal Provider As IContact)
    _provider = Provider
    End Sub


    Protected Overrides Sub CreateChildControls()
    MyBase.CreateChildControls()

    'if EmailContactDestination is a valid list, display controls
    If EmailContactDestinationIsValid() Then
    If SMTPMailHostIsValid() Then
    'create table object
    Dim oTable As New Table
    oTable.CellPadding = 0
    oTable.CellSpacing = 0

    'create a row
    Dim oContactNameRow As New TableRow
    oTable.Rows.Add(oContactNameRow)

    'create the cells and add them to the row
    Dim oContactNameLabelCell As New TableCell
    oContactNameRow.Cells.Add(oContactNameLabelCell)
    Dim oContactNameValueCell As New TableCell
    oContactNameRow.Cells.Add(oContactNameValueCell)

    oContactNameLabelCell.Width = 125
    oContactNameValueCell.Width = 350

    'create label objects for field name and field value
    Dim lblContactNameHeader As New Label
    lblContactNameHeader.Text = "Contact Name"
    lblContactNameValue = New Label
    lblContactNameValue.Text = ""

    'add the controls to the cells
    oContactNameLabelCell.Controls.Add(lblContactNameHeader)
    oContactNameValueCell.Controls.Add(lblContactNameValue)



    'create a row
    Dim oJobTitleRow As New TableRow
    oTable.Rows.Add(oJobTitleRow)

    'create the cells and add them to the row
    Dim oJobTitleLabelCell As New TableCell
    oJobTitleRow.Cells.Add(oJobTitleLabelCell)
    Dim oJobTitleValueCell As New TableCell
    oJobTitleRow.Cells.Add(oJobTitleValueCell)

    'create label objects for field name and field value
    Dim lblJobTitleHeader As New Label
    lblJobTitleHeader.Text = "Job Title"
    lblJobTitleValue = New Label
    lblJobTitleValue.Text = ""

    'add the controls to the cells
    oJobTitleLabelCell.Controls.Add(lblJobTitleHeader)
    oJobTitleValueCell.Controls.Add(lblJobTitleValue)



    'create a row
    Dim oEmailAddressRow As New TableRow
    oTable.Rows.Add(oEmailAddressRow)

    'create the cells and add them to the row
    Dim oEmailAddressLabelCell As New TableCell
    oEmailAddressRow.Cells.Add(oEmailAddressLabelCell)
    Dim oEmailAddressValueCell As New TableCell
    oEmailAddressRow.Cells.Add(oEmailAddressValueCell)

    'create label objects for field name and field value
    Dim lblEmailAddressHeader As New Label
    lblEmailAddressHeader.Text = "Email Address"
    lblEmailAddressValue = New Label
    lblEmailAddressValue.Text = ""

    'add the controls to the cells
    oEmailAddressLabelCell.Controls.Add(lblEmailAddressHeader)
    oEmailAddressValueCell.Controls.Add(lblEmailAddressValue)



    'create a row
    Dim oPhoneRow As New TableRow
    oTable.Rows.Add(oPhoneRow)

    'create the cells and add them to the row
    Dim oPhoneLabelCell As New TableCell
    oPhoneRow.Cells.Add(oPhoneLabelCell)
    Dim oPhoneValueCell As New TableCell
    oPhoneRow.Cells.Add(oPhoneValueCell)

    'create label objects for field name and field value
    Dim lblPhoneHeader As New Label
    lblPhoneHeader.Text = "Phone"
    lblPhoneValue = New Label
    lblPhoneValue.Text = ""

    'add the controls to the cells
    oPhoneLabelCell.Controls.Add(lblPhoneHeader)
    oPhoneValueCell.Controls.Add(lblPhoneValue)



    'create a row
    Dim oFaxRow As New TableRow
    oTable.Rows.Add(oFaxRow)

    'create the cells and add them to the row
    Dim oFaxLabelCell As New TableCell
    oFaxRow.Cells.Add(oFaxLabelCell)
    Dim oFaxValueCell As New TableCell
    oFaxRow.Cells.Add(oFaxValueCell)

    'create label objects for field name and field value
    Dim lblFaxHeader As New Label
    lblFaxHeader.Text = "Fax"
    lblFaxValue = New Label
    lblFaxValue.Text = ""

    'add the controls to the cells
    oFaxLabelCell.Controls.Add(lblFaxHeader)
    oFaxValueCell.Controls.Add(lblFaxValue)



    'build form to allow user to submit comments and have them emailed to selected contact

    'create a row
    Dim oMessageSubjectRow As New TableRow
    oTable.Rows.Add(oMessageSubjectRow)

    'create the cells and add them to the row
    Dim oMessageSubjectLabelCell As New TableCell
    oMessageSubjectRow.Cells.Add(oMessageSubjectLabelCell)
    Dim oMessageSubjectValueCell As New TableCell
    oMessageSubjectRow.Cells.Add(oMessageSubjectValueCell)

    'create the field label control
    Dim lblMessageSubject As New Label
    lblMessageSubject.Text = "Message Subject"

    'create the form field control
    oMessageSubject = New TextBox
    oMessageSubject.Width = 300

    'create validator
    Dim oMessageSubjectRequired As New RequiredFieldValidator

    'add controls to the cells
    oMessageSubjectLabelCell.Controls.Add(lblMessageSubject)
    oMessageSubjectValueCell.Controls.Add(oMessageSubject)
    oMessageSubjectValueCell.Controls.Add(oMessageSubjectRequired)

    'configure validator
    oMessageSubjectRequired.ErrorMessage = " * required"
    oMessageSubject.ID = "oMessageSubject"
    oMessageSubjectRequired.Display = ValidatorDisplay.Dynamic
    oMessageSubjectRequired.ControlToValidate = oMessageSubject.ID
    oMessageSubjectRequired.ValidationGroup = "EmailContactValidationGroup"





    'create a row
    Dim oSubmitterNameRow As New TableRow
    oTable.Rows.Add(oSubmitterNameRow)

    'create the cells and add them to the row
    Dim oSubmitterNameLabelCell As New TableCell
    oSubmitterNameRow.Cells.Add(oSubmitterNameLabelCell)
    Dim oSubmitterNameValueCell As New TableCell
    oSubmitterNameRow.Cells.Add(oSubmitterNameValueCell)

    'create the field label control
    Dim lblSubmitterName As New Label
    lblSubmitterName.Text = "Submitter Name"

    'create the form field control
    oSubmitterName = New TextBox
    oSubmitterName.Width = 300

    'create validator
    Dim oSubmitterNameRequired As New RequiredFieldValidator

    'add controls to the cells
    oSubmitterNameLabelCell.Controls.Add(lblSubmitterName)
    oSubmitterNameValueCell.Controls.Add(oSubmitterName)
    oSubmitterNameValueCell.Controls.Add(oSubmitterNameRequired)

    'configure validator
    oSubmitterNameRequired.ErrorMessage = " * required"
    oSubmitterName.ID = "oSubmitterName"
    oSubmitterNameRequired.Display = ValidatorDisplay.Dynamic
    oSubmitterNameRequired.ControlToValidate = oSubmitterName.ID
    oSubmitterNameRequired.ValidationGroup = "EmailContactValidationGroup"





    'create a row
    Dim oSubmitterEmailRow As New TableRow
    oTable.Rows.Add(oSubmitterEmailRow)

    'create the cells and add them to the row
    Dim oSubmitterEmailLabelCell As New TableCell
    oSubmitterEmailRow.Cells.Add(oSubmitterEmailLabelCell)
    Dim oSubmitterEmailValueCell As New TableCell
    oSubmitterEmailRow.Cells.Add(oSubmitterEmailValueCell)

    'create the field label control
    Dim lblSubmitterEmail As New Label
    lblSubmitterEmail.Text = "Submitter Email"

    'create the form field control
    oSubmitterEmail = New TextBox
    oSubmitterEmail.Width = 300

    'create validator
    Dim oSubmitterEmailRequired As New RequiredFieldValidator
    Dim oSubmitterEmailValid As New RegularExpressionValidator

    'add controls to the cells
    oSubmitterEmailLabelCell.Controls.Add(lblSubmitterEmail)
    oSubmitterEmailValueCell.Controls.Add(oSubmitterEmail)
    oSubmitterEmailValueCell.Controls.Add(oSubmitterEmailRequired)
    oSubmitterEmailValueCell.Controls.Add(oSubmitterEmailValid)

    'configure validator
    oSubmitterEmailRequired.ErrorMessage = " * required"
    oSubmitterEmail.ID = "oSubmitterEmail"
    oSubmitterEmailRequired.Display = ValidatorDisplay.Dynamic
    oSubmitterEmailRequired.ControlToValidate = oSubmitterEmail.ID
    oSubmitterEmailRequired.ValidationGroup = "EmailContactValidationGroup"

    'configure validator
    oSubmitterEmailValid.ErrorMessage = " * Not a valid email address"
    oSubmitterEmailValid.ControlToValidate = oSubmitterEmail.ID
    oSubmitterEmailValid.Display = ValidatorDisplay.Dynamic
    oSubmitterEmailValid.ValidationExpression = "\w+\w*\@\w+\w+\w*\.(com|edu|org|gov|net|corp)"
    oSubmitterEmailValid.ValidationGroup = "EmailContactValidationGroup"




    'create a row
    Dim oMessageRow As New TableRow
    oTable.Rows.Add(oMessageRow)

    'create the cells and add them to the row
    Dim oMessageLabelCell As New TableCell
    oMessageRow.Cells.Add(oMessageLabelCell)
    Dim oMessageValueCell As New TableCell
    oMessageRow.Cells.Add(oMessageValueCell)

    'create the field label control
    Dim lblMessage As New Label
    lblMessage.Text = "Message"

    'create the form field control
    oMessage = New TextBox
    oMessage.Width = 300
    oMessage.TextMode = TextBoxMode.MultiLine
    oMessage.Rows = 4

    'create validator
    Dim oMessageRequired As New RequiredFieldValidator

    'add controls to the cells
    oMessageLabelCell.Controls.Add(lblMessage)
    oMessageValueCell.Controls.Add(oMessage)
    oMessageValueCell.Controls.Add(oMessageRequired)

    'configure validator
    oMessageRequired.ErrorMessage = " * required"
    oMessage.ID = "oMessage"
    oMessageRequired.Display = ValidatorDisplay.Dynamic
    oMessageRequired.ControlToValidate = oMessage.ID
    oMessageRequired.ValidationGroup = "EmailContactValidationGroup"




    'set the text for the save button
    btnSave.Text = "Send"
    btnSave.Enabled = False
    btnSave.ValidationGroup = "EmailContactValidationGroup"

    'create the row for the save button
    Dim oRowButton As New TableRow
    oTable.Rows.Add(oRowButton)

    'create the cell for the save button
    Dim oCellButton As New TableCell
    oCellButton.ColumnSpan = 2
    oCellButton.HorizontalAlign = Web.UI.WebControls.HorizontalAlign.Right
    oRowButton.Cells.Add(oCellButton)

    'add save button to cell
    oCellButton.Controls.Add(btnSave)



    'create the row for the status message
    Dim oRowStatus As New TableRow
    oTable.Rows.Add(oRowStatus)

    'create the cell for the status message
    Dim oCellStatus As New TableCell
    oCellStatus.ColumnSpan = 2
    oCellStatus.HorizontalAlign = Web.UI.WebControls.HorizontalAlign.Center
    oRowStatus.Cells.Add(oCellStatus)

    'add status message to cell
    lblStatusMessage.ForeColor = Drawing.Color.Green
    oCellStatus.Controls.Add(lblStatusMessage)



    'add the table to the web part controls collection
    Controls.Add(oTable)
    Else
    'else display message telling user they must configure the SMTPMailHost property
    Dim lblConfigureMessage As New Label
    lblConfigureMessage.ForeColor = Drawing.Color.Red
    lblConfigureMessage.Text = "<BR><BR>" & "You must configure the SMTP Mail Host property. " & _
    "<BR><BR>" & "Please click Modify Shared Web Part -> Data -> SMTP Mail Host " & _
    "and set it to a valid SMTP mail host."
    Controls.Add(lblConfigureMessage)
    End If

    Else
    'else display message telling user they must configure the EmailContactDestination property
    Dim lblConfigureMessage As New Label
    lblConfigureMessage.ForeColor = Drawing.Color.Red
    lblConfigureMessage.Text = "<BR><BR>" & "You must configure the Email Contact Destination property. " & _
    "<BR><BR>" & "Please click Modify Shared Web Part -> Data -> Email Contact Destination " & _
    "and set it to a list based on the SentEmailsTemplate list template."
    Controls.Add(lblConfigureMessage)
    End If

    End Sub


    Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
    EnsureChildControls()

    If Not (Me._provider Is Nothing) Then
    'assign contact values to local variables
    _contactName = _provider.ContactName.Trim()
    _jobTitle = _provider.JobTitle.Trim()
    _emailAddress = _provider.EmailAddress.Trim()
    _phone = _provider.Phone.Trim()
    _fax = _provider.Fax.Trim()

    'assign contact values to labels on form
    If _contactName <> "" Then
    lblContactNameValue.Text = _contactName
    End If

    If _jobTitle <> "" Then
    lblJobTitleValue.Text = _jobTitle
    End If

    If _emailAddress <> "" Then
    lblEmailAddressValue.Text = _emailAddress
    End If

    If _phone <> "" Then
    lblPhoneValue.Text = _phone
    End If

    If _fax <> "" Then
    lblFaxValue.Text = _fax
    End If


    'enable save button if there is a value passed in otherwise disable button
    If _contactName = "" Then
    btnSave.Enabled = False

    'clear form
    ClearForm()
    Else
    btnSave.Enabled = True

    'clear status message
    lblStatusMessage.Text = ""
    End If

    End If

    End Sub 'OnPreRender


    Sub SaveAndEmail() Handles btnSave.Click
    'save message to the specified list library
    SaveMessage()

    End Sub


    Private Sub SaveMessage()
    'PURPOSE: save values from form into list library ContactUs

    Try
    'get the site the web part is running on
    Dim oWeb As SPWeb
    oWeb = Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(Context)

    'get the list where we want to save the form values to
    Dim oList As SPList
    oList = oWeb.Lists(EmailContactDestination)

    'create a new list item
    Dim oNewItem As SPListItem
    oNewItem = oList.Items.Add()

    'populate the new list item with values from the form
    oNewItem.Item("Message Subject") = oMessageSubject.Text
    oNewItem.Item("Submitter Name") = oSubmitterName.Text
    oNewItem.Item("Submitter Email") = oSubmitterEmail.Text
    oNewItem.Item("Message") = oMessage.Text
    oNewItem.Item("Contact Email") = lblEmailAddressValue.Text

    'update the list with the new item
    oNewItem.Update()

    'email the message to the designated contact
    EmailMessage()

    Catch ex As Exception
    Dim lblErrorMessage As New Label
    lblErrorMessage.ForeColor = Drawing.Color.Red
    lblErrorMessage.Text = "Error: " & ex.Message & _
    "<BR><BR>" & "Details: " & ex.ToString
    Controls.Add(lblErrorMessage)

    End Try

    End Sub


    Private Sub EmailMessage()
    'PURPOSE: email the contact that was selected

    Dim strFromName As String = oSubmitterName.Text
    Dim strFromEmail As String = oSubmitterEmail.Text
    Dim strSubject As String = oMessageSubject.Text
    Dim strMessage As String = oMessage.Text
    Dim strToName As String = lblContactNameValue.Text
    Dim strToEmail As String = lblEmailAddressValue.Text

    Try
    'build from email address and to email address
    Dim FromEmailAddress As New Net.Mail.MailAddress(strFromEmail, strFromName)
    Dim ToEmailAddress As New Net.Mail.MailAddress(strToEmail, strToName)

    'create email and assign its subject and body
    Dim MailMsg As New MailMessage(FromEmailAddress, ToEmailAddress)
    MailMsg.Subject = strSubject
    MailMsg.Body = strMessage

    'create smtp email object
    Dim smtpmail As New SmtpClient

    'set email's smtp server
    smtpmail.Host = SMTPMailHost

    'send email
    smtpmail.Send(MailMsg)

    'clear form
    ClearForm()

    'display success message
    lblStatusMessage.Text = "Message Sent Successfully!"

    Catch ex As Exception
    Dim lblErrorMessage As New Label
    lblErrorMessage.ForeColor = Drawing.Color.Red
    lblErrorMessage.Text = "Error: " & ex.Message & _
    "<BR><BR>" & "Details: " & ex.ToString
    Controls.Add(lblErrorMessage)

    End Try
    End Sub


    Private Sub ClearForm()
    'PURPOSE: clear form of all values

    'clear selected contact person's info
    lblContactNameValue.Text = ""
    lblJobTitleValue.Text = ""
    lblEmailAddressValue.Text = ""
    lblPhoneValue.Text = ""
    lblFaxValue.Text = ""

    'clear form fields
    oMessageSubject.Text = ""
    oSubmitterName.Text = ""
    oSubmitterEmail.Text = ""
    oMessage.Text = ""

    End Sub


    Private Function EmailContactDestinationIsValid() As Boolean
    'PURPOSE: returns true if specified email list is valid for the web part

    Try
    'get the site the web part is running on
    Dim oWeb As SPWeb
    oWeb = Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(Context)

    'get the list specified by user in property, if list is not found in site, flow will hit Catch
    Dim oList As SPList
    oList = oWeb.Lists(EmailContactDestination)


    'check if fields exist in list

    Dim blnMessageSubjectFound As Boolean = False
    Dim blnSubmitterName As Boolean = False
    Dim blnSubmitterEmail As Boolean = False
    Dim blnMessage As Boolean = False
    Dim blnContactEmail As Boolean = False

    'loop through the fields in the list and check to see if all the required fields are in the list
    For Each oField As SPField In oList.Fields
    If Not oField.Hidden And Not oField.ReadOnlyField And oField.Type <> SPFieldType.Attachments Then

    If oField.Title = "Message Subject" Then
    blnMessageSubjectFound = True
    End If

    If oField.Title = "Submitter Name" Then
    blnSubmitterName = True
    End If

    If oField.Title = "Submitter Email" Then
    blnSubmitterEmail = True
    End If

    If oField.Title = "Message" Then
    blnMessage = True
    End If

    If oField.Title = "Contact Email" Then
    blnContactEmail = True
    End If

    End If
    Next

    'if all fields were found, return true
    If blnMessageSubjectFound And blnSubmitterName And blnSubmitterEmail And blnMessage And blnContactEmail Then
    Return True
    Else
    Return False
    End If

    Catch ex As Exception
    Return False

    End Try

    End Function


    Private Function SMTPMailHostIsValid() As Boolean
    'PURPOSE: returns true if SMTP Mail Host is valid

    Try
    If SMTPMailHost <> "" Then
    Return True
    Else
    Return False
    End If

    Catch ex As Exception
    Return False

    End Try

    End Function

III. Finally, we deploy the web parts to the SharePoint site, add them to a page, configure them, connect them to each other, then test them!
  1. in Visual Studio 2008, hit F5 (this should build and deploy the web parts to your site)
  2. in your SharePoint site, select the page you want the web parts on, then click Site Actions -> Edit Page
  3. click Add A Web Part
  4. scroll down to the Miscellaneous section, select ContactList web part and EmailContact web part, then click Add
  5. In the ContactList Web Part, click Edit -> Modify Shared Web Part -> Data, and in Contact List Data Source, type our custom contact list we created, Contact List and hit OK. You should see the people you entered into the list appear in the web part.
  6. In the EmailContact Web Part, click Edit -> Modify Shared Web Part -> Data, and in Email Contact Destination, type our custom email list we created, Sent Emails and hit OK. Next, enter your SMTP Mail Host in the next textbox. If you don't have your server configured for this, just type anything as the validation function in the code just expects any value. If you put in something that isn't your host, the web part just won't be able to email. You can customize the validation code yourself to indicate what you expect the user to enter.
  7. click the Email Contact web part and click edit -> Connections -> Get Contact Consumer From -> Contact List (you could also have set the connection up from the Contact List web part as well)
  8. Click Exit Edit Mode
  9. Test the connected web parts by clicking a person in the Contact List and watching them appear in the Email Contact web part! In the Email Contact web part, enter in values and hit Send. This will save the message in the Sent Emails list. If you set up the SMTP mail host properly and the selected person has a proper email address, then that person will also be emailed the message you entered.
So there you have it! Now, exactly what is happening? In the ContactList web part, we created properties that implemented the interface IContact. The ConnectionProvider function ProvideIContact is what returns the interface. Originally, all the properties are empty, so this function won't have any values. When a contact is clicked, the ContactSelected routine fires off and populates the properties, so now ProvideIContact can return something. Now, the EmailContact web part has a ConnectionConsumer routine GetIContact that gets the values from ProvideIContact. Essentially, when we created a connection between the two web parts on step 7 above, we created a bridge between them via ContactList's ProvideIContact and EmailContact's GetIContact. As a side note, there is an interface called IWebPartRow, and I believe there would be a way to use that instead of the individual properties I created in IContact, but I went with the properties in IContact because it seemed easier at the time. Well, I hope this worked well. If you followed along and it didn't work, let me know in case I forgot something. However, I am pretty sure this should work 100%!

2 comments:

  1. Nice Article. It helped me a lot. Good job.

    ReplyDelete
  2. Please give some advise - how you get in Visual Studio 2008 conectivity with SharePoint ? I have installed VS 2008 but in project select i not have "SharePoint" case :(

    ReplyDelete