This is a quick overview on how to add a column’s description to your custom edit and disp forms in SharePoint 2007.

List Name: Projects
Column Name: Status
Column Type: Lookup
Column Description: “Choose the status for this current project.”

To add a column to a form and display it’s contents, it’s pretty straight forward:

SPWeb web = SPContext.Current.Web;
SPList projects = web.Lists["Projects"];
SPListItem item = projects.GetItemById(Convert.ToInt32(Request.QueryString["ID"]));
 
// use this to grab the value, you can get either the ID or the Value in the column
SPFieldLookupValue status = new SPFieldLookupValue(Convert.ToString(item["Status"]));
lblStatus.Text = status.LookupValue;
 
// use this to grab the columns description, or any other property for that column
SPFieldLookup statusDesc = new SPFieldLookup(projects.Fields, "Status");
lblStatusDesc.Text = statusDesc.Description;

The above works great, but please note that the column name for the SPFieldLookup method requires the SharePoint Internal Field Name. So for example, if your column name was Project Status, and you created the column with the spaces, then it will be Project_x0020_Status.

Tagged with:  

Hiding columns in SharePoint is nothing new really, there have been several articles written on this topic. The approach for doing this, however, does inspire some debate in terms of what the best practice is. Let’s say we can agree that there are three ways to get this done:

  1. Using the built in content types to specify which columns you wish to be hidden.
  2. Using jQuery and a content editor web part to hide the columns as desired.
  3. Hide the columns programmatically using code.

I just wanted to make some comments on all three. The content type approach is a good one and relatively simple to implement. Once you’ve enabled content types for your list or library, click on the default content type, let’s say it’s Item, and choose the column you’d like to have hidden and simply set it’s column settings to Hidden. Here is an excellent reference for this technique: http://littletalk.wordpress.com/2009/03/30/hide-remove-title-column-from-sharepoint-list/.

Ok so the above works good, but what happens if you only want to introduce these hidden columns on your New and Edit forms but not your Disp form as an example. Or what if your scenario requires that they are hidden from all default New, Edit and Disp forms, but you have some custom SharePoint Designer disp forms that you’ve created that those fields need to be visible on. The content type approach will hide the column for all forms and so that won’t always work. We need something more granular.

So there is where the jQuery approach comes in handy. Some great resources for this:

As per the comments by Nathan Ahlstrom in the second link noted above, the final fix for me was to use:

<script type="text/javascript">
$(document).ready(function() {
    $('nobr:contains("Completion time")').closest('tr').hide();
    $('nobr:contains("Score")').closest('tr').hide();
});
</script>

Please note that I had to add quotes around the tr tag for this to work for me.

The final approach uses some custom code and the object model to hide columns for a given list. http://www.sharepointkings.com/2008/05/how-to-hide-column-of-sharepoint-list.html. Now I’m not entirely sure how this works with custom forms besides the New, Edit and Disp forms, and until I have time to try out, I won’t know the answer to that. It’s worth mentioning because it does give you some granularity in that you can specify hidden properties per form.

That’s all for now. Please send in your comments if you have them, would love to hear from you.

Tagged with:  

Alright, today’s blog post is going to be a bit infrastructure related. More specifically, I’d like to document an issue we encountered recently trying to do a restore from a production server to one of our development boxes. We do this often to keep our development data fresh and in sync with production, otherwise it becomes difficult to do any sort of real testing with numbers. Usually, this is a pretty standard procedure for us:

  1. Within Central Administration, under Application Management, we navigate to Content databases
  2. Making sure to select the Web Application we plan to restore to, we click on the WSS_Content link (or whatever happens to be the name of your db)
  3. Within the Manage Content Database Settings page, change the Database status drop down from Ready to Offline
  4. From here I stop the IIS Web Site, restart SQL Server and kick off my restore
  5. Once the restore is complete, I head back into my Manage Content Database Settings page and switch the Database status back to Ready

Now usually this works without issue. But recently, while attempting to do this on a machine we hadn’t worked with on a few weeks, we were encountering all sorts of errors trying to navigate to our site collection. Specifically, we were seeing the following error in the Operations logs:

The specified SPContentDatabase Name=WSS_Content Parent=SPDatabaseServiceInstance Name=Microsoft##SSEE has been upgraded to a newer version of SharePoint. Please upgrade this SharePoint application server before attempting to access this object.

Based on this error, my first thought was to check the dbo.Versions table to see if perhaps we had a conflict in versions as this error would suggest. Unfortunately, trying to read from the dbo.Versions table resulted in this pretty error:

Msg 33002, Level 16, State 1, Line 1
Access to table dbo.Versions is blocked because the signature is not valid.

So now we’re having fun at this point. I can’t read from the dbo.Versions table, so I don’t really know what the patch level of this particular server is. After checking production, I know that my patch level is 12.0.0.6504. In order to cross check what this means, you should have this link handy from the SharePointDevWiki.

Based on what I was reading there, my production server had the: MOSS 2007 or WSS 3.0 April 2009 Cumulative update. I know I probably could have done the research and checked file versions, but why should I have to do that when all I really needed to do was read from dbo.Versions? After a bit of troubleshooting, I realized it would make the most sense to simply spin up a new Web Application and fresh content db on my development box and read ITS dbo.Versions table. Turns out that original error was right on the money, my development box was one version behind: 12.0.0.6421.

Once I upgraded to the missing cumulative update and tried my restore process again, everything was back to normal! I hope that helps someone understand what the dbo.Versions table is all about, and what you can do to get past these errors.

Tagged with:  

If you’re like me and you do a fair bit of object model programming, you’ve likely seen this error before. More specifically, the error is as follows:

Unhandled Exception: Microsoft.SharePoint.SPException: Invalid data has been used to update the list item. The field you are trying to update may be read only.

There are probably more than one cause for this particular issue, but in my case, it always comes down to an error in the way I’ve assigned a field of type Lookup.

So to set up our scenario, let’s say we have a custom list called Types, and it contains 3 items:

  1. Employee
  2. Contractor
  3. Manager

Now let’s assume we’ve created a custom list called Users and it contains a column called User Type of type Lookup that points to the Types list using the Title column.

If we’re doing some updates to our list programmatically, we’ll need to be able to set the Type column. Your typical scenario is that you’re reading this from a form control and populating this field. In my case, I knew specifically what value I wanted to set. So let’s start with something like this:

1
2
3
SPListItem item = list.Items.Add();
item["Type"] = "Employee";
item.Update();

Unfortunately, the above bit of code will fail with the error outlined at the beginning of this post. The data we’re attempting to assign is not valid. What we need to do is create another object, an SPFieldLookupValue object to be more specific, and use one of the constructors to build the lookup that we’ll then assign to our field.

1
2
3
4
SPListItem item = list.Items.Add();
SPFieldLookupValue lookup = new SPFieldLookupValue(1, "Employee");
item["Type"] = lookup;
item.Update();

I’m not satisfied with the above, because it’s forcing me to hard code the id and the value. I am interested in some feedback from my readers — does anyone have a better approach to this problem? I’ll be awarding a free Black Ninja TSHIRT to the reader who can provide me the most elegant workaround.

Tagged with:  

I’m very excited and I consider myself quite lucky to be able to attend the Microsoft SharePoint 2009 Conference in October. I’ve already been to a couple great conferences this year, but I am quite confident this will be a good one. I’m looking forward to seeing all that 2010 has to offer.

If you haven’t already, you might want to check out the preview videos over at the Microsoft SharePoint site.

Tagged with:  

I’ve been working over the past few days with a custom workflow I’m building in Visual Studio 2005 that’s responsible for notifying users when specific criteria was met. Inside the workflow, I have a few sendEmail functions responsible for building the content within the email message:

1
2
sendEmail1.Body += "<font face=\"Arial\">This is the body of my email.<br/><br/>";
sendEmail1.Body += "Adding some information for users that will describe some detail about this item.</font>";

The above worked well until I started to see some truncating in my emails. I did some comparisons and found that the truncating would occur when the character count exceeded 2048 characters. I figured this couldn’t be the limit for a string in .NET so I did a bit of digging around and finally discovered that the root of the issue was because I didn’t have any line breaks in my string: “\r\n”. Once I inserted those at specific intervals, the truncating disappeared.

Awesome! Hope this helps someone else out there.

Tagged with:  

Triggering SharePoint workflows programmatically from within a custom built Visual Studio workflow is not difficult once you know where to look. Tony Testa wrote a great post on this very same thing that describes these concepts in more detail than I will — so go check that out if you haven’t already. I had to tweak his concept a little bit because I was doing this within an already running workflow that belonged to a content type not a list.

So in my scenario, I had a single workflow tied to a Content Type, and because I knew there was only one workflow, I used index at 0 to get the current workflow association. If your workflow is tied to a list, then you may not need to call ContentType, you might be able to use:

1
SPWorkflowAssociation workflowAssociation = workflowProperties.List.WorkflowAssocations[0];

If you have multiple workflows tied to a Content Type or a List, you will need to grab the Guid associationId for that workflow instead of using the index.

Finally, once I have my workflow association configured, I can start my workflow by passing it the parameters it needs:

1
2
3
4
5
if (workflowProperties.Site.WorkflowManager.GetItemActiveWorkflows(setLeaderItem).Count == 0)
{
    SPWorkflowAssociation workflowAssociation = workflowProperties.Item.ContentType.WorkflowAssociations[0];
    workflowProperties.Site.WorkflowManager.StartWorkflow(setLeaderItem, workflowAssociation, workflowAssociation.AssociationData, true);
}

The IF block is there to check if any active workflow are running on that list item. If there aren’t, it attempts to start the workflow. There you have it! That should trigger the workflow on the list item you specified.

Tagged with:  

Problem

You’ve developed some custom new, edit and display application pages that are stored in the _layouts directory. Let’s assume the filenames are newform.aspx, dispform.aspx and editform.aspx. You now want to change the properties of your custom list so that any new, edit or display requests point to your custom pages.

If you open up your site within SharePoint Designer and expand the Lists folder, from there you can access the properties of that custom list by right clicking on it and selecting Properties. Once the List Properties pane is open, click on the Supporting Files tab.

You’ll see there that you can actually choose what display, edit and new forms you want your list to be using. So if you’ve developed something custom, you would click Browse…, point to your new location and select the file. Here is where it starts to fail, I am only able to browse within the site itself and cannot navigate to my _layouts directory to select the files I mentioned above.

Solution

I suspected this was a limitation of the SharePoint Designer UI and not actually a limitation of the Object Model. I did a bit of fiddling with my SPList object and was not able to find anything that let me change those properties. If you look at the screenshot above, there is a key piece of information that’ll make the light turn on (at least it did for me). The Supporting Files tab has a drop down selector for the Content type specific forms. If you think about that a moment, you’ll remember that ALL lists within SharePoint inherit from a default content type.

So armed with that knowledge, I created an SPContentType object and took a look at it’s properties and methods. Sure enough, there are 3 properties I can set to change these forms: EditFormUrl, NewFormUrl and DisplayFormUrl. Here is some sample code I used to change the forms for my custom list called ‘My List’ that inherits from the Item content type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SPWeb web = SPContext.Current.Web;
 
web.AllowUnsafeUpdates = true;
 
SPList list = web.Lists["My List"];
 
SPContentType ct = list.ContentTypes["Item"];
 
ct.EditFormUrl = "_layouts/editform.aspx";
ct.NewFormUrl = "_layouts/newform.aspx";
ct.DisplayFormUrl = "_layouts/dispform.aspx";
 
ct.Update();
list.Update();

So in the example code above, I had to determine what default content type my list inherited from. In this case it was the Item content type.

NOTE: If you need to change the content type directly, you can definitely do that, however, I did a bit of testing and found that any lists ALREADY inheriting from that content type did not pickup my changes to the form locations. Any NEW list that I created that was inheriting from that content type did pickup the changes. In order for me to change the form locations for the existing list I had to use the code above. For reference, here is how you would change the content type directly. The code has only a subtle difference.

1
2
3
4
5
6
7
8
9
10
11
SPWeb web = SPContext.Current.Web;
 
web.AllowUnsafeUpdates = true;
 
SPContentType ct = web.ContentTypes["Name Of Your Content Type"];
 
ct.EditFormUrl = "_layouts/editform.aspx";
ct.NewFormUrl = "_layouts/newform.aspx";
ct.DisplayFormUrl = "_layouts/dispform.aspx";
 
ct.Update();

As always, any questions, let me know!

Tagged with:  

Hey all, I just wanted to point out a sneaky little problem we ran into today at work. I’ll outline it briefly here, but Donabel wrote a great summary that we’ve posted on the Black Ninja blog.

The problem to be aware of is related to SPQuery objects that have the LookupId set to TRUE and the Value Type set to Lookup. An example:

1
2
3
4
SPQuery oQuery = new SPQuery();
 
oQuery.Query = "<Where><Eq><FieldRef Name='Employee' LookupId='TRUE'/>" +
            "<Value Type='Lookup'>161</Value></Eq></Where>";

With a NON indexed column, the above query works fine. Once you change the Employee field so it is an indexed column, the above query will fail to work. Changing Value Type from Lookup to Integer seems to make it work again. So somehow, something is changing when a column is indexed thus causing the query to behave strangely.

Removing the index on that column makes everything work magically again. Thanks to the following post for affirming what we had already painfully discovered.

Tagged with:  

I recently wrote an article that outlined a recent optimization effort using the ANTS Profiler and it’s finally been published! If you’re having any performance issues at all in your custom SharePoint Applications, you should take a few minutes and check this out. My aim was to share my experiences and hopefully to generate some interest in application profiling.

http://www.simple-talk.com/dotnet/.net-tools/working-with-the-ants-profiler-to-optimize-sharepoint/

Tagged with: