Tuesday, June 23, 2009

How to set a SharePoint web part's list at run time

Let's say you have a web part that must have a particular custom list you created in order for the web part to function. For instance, in the web part's CreateChildControls() routine, maybe you have some code similar to this:


'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("Contact List")

...other code that loops through oList and displays the different field values...

So in the above example, the required custom list is called "Contact List". You may run into a few problems with this:
  1. What if the required list doesn't exist?
  2. What if the list exists, but it doesn't have the fields needed by the web part?
  3. Every time you drop the web part on a page, it must have that list when it might be beneficial to have some flexibility with the list the web part is pointing to. A good example of this would be a site with a Marketing page and a Sales page. On the Marketing page, you want to display Marketing Contacts and on the Sales page you want to display Sales Contacts. Marketing Contacts and Sales Contacts are two separate lists.
My solution to this has a few steps.

First off, we need to create a custom property for your Contact List web part. Below is the code for the custom property.


Dim strContactListDataSource As String = ""

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

So, the above code will add a new property called Contact List Data Source to the web part's properties you see when you click the web part in Edit Mode and click Modify Shared Web Part. Scroll down to the section Miscellaneous and you will see it. (Currently it is simply a textbox but it is possible to make it a dropdown list that lists available lists on the site).

Now, if we go back to the first code snippet above that gets the list, we just change it to reference our new property:


'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)

...other code that loops through oList and displays the different field values...

While this makes my web part dynamic in terms of what list to look at, I still have a problem. What if the user just added the web part to a page? The property is going to be empty initially until the user sets it. So what does the user see? Or, what if the list the user specifies in the property does not exist or is an invalid list?

So, the next thing I do is create a function called ContactListIsValid() which will test to make sure the ContactListDataSource property the user specified is valid. If it is, the function will return true and the above code snippet will fire. If it is not valid, the function will return false and code will fire off that displays a message to the user telling them they need to set the ContactListDataSource property to a valid list.

First, you will see ContactListIsValid(), then below that I will show you how I use it for displaying error messages. Note that this function verifies the list exists and has the required fields.


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

Finally, below is the code on how I use this in 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)

...other code that loops through oList and displays the different field values...

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 -> Miscellaneous -> Contact List Data Source " & _
"and set it to a list based on the ContactListTemplate list template."
Controls.Add(lblConfigureMessage)
End If

A final thought. Notice the error message tells the user to set the property to a list based on the ContactListTemplate list template. I created a list template from the Contact List custom list, so that way the user can create their contact list from the list template to make sure they have all the necessary fields. To do this, I went to the List Settings of Contact List and selected Save As List Template.

Well, that's it! I wouldn't be surprised if people have their own way of doing all this, but I like to go for the simplest, most direct approach. I hope this helps!

3 comments:

  1. I can't find the Miscellaneous section in Edit mode of the webpart, can you help? My webpart is an ajax enabled webpart in which I am using Accordion to display list items.

    ReplyDelete
  2. Ok, I figured out, I didn't declare it as public so Miscellaneous section was not showing up at all.

    ReplyDelete
  3. Kentico 12 migration I think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article.

    ReplyDelete