SharePoint List Validation

I had a need to be able validate a date against another date on a list when it was created, basically I wanted the second to date to be on or after the first date. Traditionaly, this sort of thing was handled through event receivers attached to the list, but it always felt like overkill.

It was only when looking through the List Settings page that i noticed the Validation settings section that i’ve never really looked at before. This section allows you to create a Formula (think Excel) using multiple colums. The formula is validated at list entry time and if the formula returns false, the user message you specify is displayed to the user.

My particular validation was around ensuring that the Position End Date (if populated) was on or after the Position Start Date, to do this through the Validation Settings page, I add to enter the following formula:

=OR([Position End Date]>=[Position Start Date],(COUNT([Position End Date])=0))

This is showing an OR condition, where the Position End Date must be on/after the Position End Date OR the Count of the number of entries in the Position End Date is 0. This was the only way I found of checking whether a date had been emptied as empty string or null didn’t seem to work, presumably because of DateTime type constraints.

This worked fine for manually configuring validation on lists that already exist, but if you want to do this at list provisioning time, you can add it in the list schema just after the ContentTypes node, just like this:

    <ValidationMessage=The position end date must be on or after the position start date>

=OR(ExpPositionEndDate >= ExpPositionStartDate,(COUNT(ExpPositionEndDate)=0))

</Validation>

Note, that you have to use the internal name for the columns when configuring through the schema.xml.

Geek Library for Windows Phone 7 is live!

At last my very first app for Windows Phone 7 has gone live! Its actually a major milestone for me as not only have I actually finished something, but its my first every release of something into a public marketplace (apart from my kids of course…).
I’ve really enjoyed developing this, trying to use it as a learning experience for developing with Silverlight for Windows Phone 7 and putting in as many bells and whistles as I could. The fact that it passed certification first time shows the effort I put in!
I’ve included the marketplace spiel below and a link to try the free trial, so please give it a go and let me know what you think! I’ll be fully supporting and updating the app so any feedback is much appreciated!
Here you go:

Geek LibraryGeek Library helps you to keep track of your entire library of books, movies, music and video games on your phone and optionally backed up to the cloud.  Scan an item or search a huge online database and pull back cover art and details. Add the item to your library or add it to a wishlist and keep track of the best deals available. Rate your stuff, update the details and add your own cover art if you want.

Here is a list of what you can do with your very own Geek Library:

* Sync to/from the cloud
* Supports multiple languages and locale switching for getting deals from different territories
* Mark things as up for sale/sold/loaned to a friend
* Keep a playlist of things you haven’t read/played
* Rate all your items
* Quickly see loaned items and who has them!
* Fast app switching

Coming soon:

* A desktop client that syncs between the cloud and your phone
* Selling items direct from the app
* Live tiles straight to your playlists

Performance progress bar not displaying after updating to Mango

I’ve been busy over the last few weeks trying to finish my Windows Phone 7 app and recently decided to take the plunge and update it to run on the upcoming Mango release.

Surprisingly I haven’t had too many problems. The only thing that caught me out was remembering to also recompile all the various utility dlls that I had included in my solution and forgot that I was still using! For example, I had included in my solution the Silverlight ZXing, so I had to download the source for that and upgrade it to 7.1.

One thing that did catch me out was that after upgrading everything to 7.1, my performance progress bar (installed from the Augustrelease of the Silverlight Toolkit for Windows Phone) had stopped displaying when the app was busy doing something.

I use the performance progress bar bound to a property in my view model and toggle the display through raising property change events on the property. Everything else was updating correctly just the performance progress bar wasn’t. It turns out that this is a bug in the August release of the toolkit with the performance progress bar and will be fixed in a future release.

To temporarily get around this and fix this I added the following code in the page loaded event in my code behind for my view to reset the binding on the performance progress bar once the view had loaded.

// Following code is required to fix bug in Windows Phone Toolkit - August 2011 
if (progressBar != null)
{
     progressBar.SetBinding(PerformanceProgressBar.IsIndeterminateProperty, new Binding("Busy"));
}

This basically rebinds the IsIndeterminate property of the progress bar to the property in my view model called “Busy”. After doing that the performance progress bar shows/hides correctly.

Binding an MVVM Command to a listbox item

If you are trying to bind a Command to a listbox item that is on a View bound to a ViewModel, you may have been banging your heard trying to work out why the Command wasn’t firing ( I was anyway! ). The problem is that Silverlight is trying to find the Command in the context of the control within which it is bound. So in my instance, it was trying to find the Command within the ItemSource of the listbox, rather than looking in the ViewModel which is where definition for my Command exists.

Fortunately, I’m using the MVVM Light Toolkitframework  for my MVVM implentation in my Windows Phone 7 app. This has a really simple feature where you can find the ViewModel through a ViewModelLocator, so the binding on my EventToCommand becomes:

<GalaSoft_MvvmLight_Command:EventToCommand
Command="{Binding Source={StaticResource Locator}, Path=Main.DeleteCommand, Mode=OneWay}"/>

where Main is the name of my ViewModel. Simple!

InfoPath form deployment errors to SharePoint

I’ve spent a little while trying to get to the bottom of a deployment problem when updating an existing InfoPath form that had previously been deployed to a SharePoint site via a feature. The change was a simple textual change, adding some descriptive text to the top of a form. Simple you might think…

Actually making the change was easy enough, I opened the design form from within Visual Studio. Interestingly even though I had double-clicked the file from within my source tree it was actually opening it from a path that was stored within the file. Saving the form template to my source tree has got around that. Its something that I wouldn’t have noticed apart from the fact that the location it was actually opening it from was write-protected and hence it couldn’t save it. Otherwise I would have made my changes and blindly checked it in thinking I was actually checking in my files. It would have appeared to have worked but the actual changes would have been in a file that wasn’t under source control!

I then published the form template to where it was stored in TFS in my feature folder. I wasn’t sure what options had been previously used during the original publishing so I just accepted the defaults (this was where I went wrong…). I then updated my wsp and upgraded my feature. Upgrading didn’t work as the file is actually uploaded into SharePoint via a module definition so I had to change my deployment to do a retract/redeploy instead. I realised this as post upgrading nothing seemed to have changed within the form. After doing a retract/redeploy I now got something different which was basically a ‘form has been closed’ error on trying to access any workflows that were using this form.

Doing some digging using the following useful stsadm command:

stsadm.exe -o verifyformtemplate -filename <complete path to your xsn including the name.xsn>

I got the following back:

FatalErrorNoThrow : This form template has not been correctly published to be browser-enabled. Open the form template in InfoPath Design mode, and click Publish Form Template in the Design task pane. Follow the steps in the Publishing Wizard to republish the form template, and then try again.

Well I did this many times, trying different combinations of settings, even trying to modify the access location to be the path to the installed feature in the 12 hive. I thought this might be something to do with the fact that it was originally trying to open it from a different source location and I thought it might be something to do with me moving it to my source location however nothing seemed to work. I then did some more searching and came across a really good post by Sahil Malik that explains the correct process to follow to deploy InfoPath forms via features, and in there he mentions leaving the access path blank, as this information is stored in the feature. This was the key thing that I was doing wrong. It appears that anything you put in the Access Path property during the Publishing path overrides what is supplied in the feature and stops the form from deploying correctly, in fact if you go to the Manage Form Templates page within Central Administration you will see your deployed form stuck in a Status of Installing and the Workflow enabled option will be No.

Here is a link to Sahil’s post as it really explains in good detail the correct process to follow to deploy InfoPath forms using features:

http://blah.winsmarts.com/2008-8-Deploying_InfoPath_2007_Forms_to_Forms_Server_-and-ndash_Properly.aspx

Blanking the access path and then rebuilding my wsp, retracting/redeploying and now everything works. Existing workflows have been updated and new ones pick up the new form too. Finally, and all I was doing was adding some text to the form… 🙂

SharePoint recurrence data schema

I have been hunting high and low for some definition of the schema used to populate the RecurrenceData field of an event in a SharePoint calendar. It seems to be one of life’s great mysteries…

Today, I finally stumbled across an msdn blog post that explains how to export SharePoint calendar events to iCal format files. I’m sure that this is the only post in the entire Internet (except for mine now of course…) that contains some really useful nuggets about what you need to set on your SPListItem when creating an event through code. I’ve included a link to the article at the end of this post, but just in case I’ve also copied a bit of it here…

<Updated> I’ve just added a section about deleting individual events from a recurring series. This took a bit of figuring out! </Updated>

Distinguishing between calendar item types

Calendar items in SharePoint fall into several categories. Single events are those which don’t repeat and only appear once on the calendar, while recurring events may show up any number of times depending on the recurrence pattern selected by a user. Either type of event may have a defined start and end time, or it may be an all-day event which lasts from midnight to 11:59 PM.

Furthermore, individual instances of a recurring event may be deleted or edited, creating a new event which takes its place. The event created by a deleted instance instructs the calendar not to render that day’s instance of the recurring event.

Calendar events can be distinguished by looking at the fRecurrence, fAllDayEvent, and EventType field values:

Type Description fRecurrence fAllDayEvent EventType
Single event An event created with the All Day Event and Recurrence checkboxes unselected. False False 0
All-day event An event created with the All Day Event checkbox selected. False True 0
Recurring event An event created with the Recurrence checkbox selected. Has a recurrence icon in the All Events view. Appears as a single master event on the All Events view, but as recurring instances on the Current Events and Calendar views. True False 1
Recurring all-day event Same as above, but with the All Day Event checkbox selected at creation time. True True 1
Recurrence exception Created by editing an instance of a recurring event. Has a strikethrough recurrence icon in the All Events view. True False 4
All-day recurrence exception Same as above, but created by editing an instance of an all-day recurring event. True True 4
Deleted instance of a recurring event Created by deleting a instance of a recurring event. Title is prefixed with “Deleted:” in the All Events view, and is hidden in the Current Events and Calendar views. True False 3
Deleted instance of an all-day recurring event Same as above, but created by deleting an instance of an all-day recurring event. True True 3

Understanding recurring events

Recurring events have a number of subtleties not found in single events. Most importantly, one recurring event item expands into any number of recurring event instances when it is rendered in the calendar view. Recurring events also make use of fields left empty in single events.

Certain fields are interpreted differently depending on whether the item in question is a recurring event or a single event:

Field Value for single event Value for recurring event
EventDate Start date and time Start date and time set for the recurring event when it was created, which may be an earlier date than the first instance of the recurring event.
EndDate End date and time End date and time for the last instance of the recurring event. For recurring events with no end date, this is a computed date several years in the future.
Duration The time in seconds between EventDate and EndDate. The duration in seconds of an individual instance of the recurring event.

Recurrence patterns and expanding events

Recurring events store the pattern used to display instances of the recurring event as XML in the RecurrenceData field. While this data is best used in a read-only fashion, the following are examples of the patterns you may encounter:

Recurrence type RecurrenceData field value
Daily every 1 days, no end date <recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><daily dayFrequency=”1″ /></repeat>

<repeatForever>FALSE</repeatForever>

</rule></recurrence>

Weekly every Monday, Tuesday, and Wednesday, end by 5/31/2007 <recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><weekly mo=”TRUE” tu=”TRUE” we=”TRUE” weekFrequency=”1″ /></repeat>

<windowEnd>2007-05-31T22:00:00Z</windowEnd>

</rule></recurrence>

Monthly the third Wednesday of every 2 months, no end date <recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><monthlyByDay we=”TRUE” weekdayOfMonth=”third” monthFrequency=”2″ /></repeat>

<repeatForever>FALSE</repeatForever>

</rule></recurrence>

Yearly every May 18, end after 10 instances <recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><yearly yearFrequency=”1″ month=”5″ day=”18″ /></repeat>

<repeatInstances>10</repeatInstances>

</rule></recurrence>

Deleting individual events from a recurring series

In order to delete an individual event from a recurring series, you actually need to create a new event and set a few properties on it to link it up to a specific instance from the ‘owning’ series. You will need to set the following properties (You need all of them!):

  • MasterSeriesItemID
    • Set this to the ID of the owning calendar list item
  • UID
    • Set this to the UID of the ownding calendar list item. If you haven’t populated this column in your owning list item, you’ll be having all sorts of problems already…
  • EventType
    • Set this to 3 to mark it as a deleted record
  • fRecurrence
    • Set this to 1
  • fAllDayEvent
    • Set this to the fAllDayEvent property of the owner calendar list item
  • EventDate
    • Set this to the date of the event instance you want to delete
  • EndDate
    • Set this to the date of the event instance you want to delete
  • RecurrenceID
    • Set this to the date of the event instance you want to delete. (Yep, this is the one that caught me out…has to be set to a datetime and NOT an ID)
  • Title
    • Set this to the title of the owner calendar event, but prefixed with Deleted:

When you have done this, you should now see an additional event in the All Events view of the calendar with a title of “Deleted: Name of your event” and the date of the specific instance. In the Calendar view, the specific instance should be invisible. This means that if you want to undo your deleted instance, you simply delete the extra list item that you have created and it will reappear!

Response.End terminating page events within a sharepoint page

I had a need to be able to present the user of a website with a prompt to open/save a pdf that had been dynamically generated based on inputs from the user during the completion of a form.
I wasn’t able to navigate away from the page where this option to download the pdf was presented to the user as i needed to remain within the context of the particular section within the form. Therefore the easiest way to provide the open/save option was through modifying the Page.Response as follows:

Page.Response.ContentType = “application/pdf”;

Page.Response.AddHeader(“content-disposition”, “attachment;filename=” + this.FormControl.FormDefinition.Name + “.pdf”);

Page.Response.Buffer =true;

Page.Response.Clear();

Page.Response.OutputStream.Write(PdfBuffer, 0, PdfBuffer.Length);

Page.Response.OutputStream.Flush();

Page.Response.Flush();

This worked fine, the user would click on a download button, the open/save box would pop up and the pdf would be streamed exactly as I wanted it. However, when they closed the open/save box and returned to the page with the download button on, none of the buttons on the page would work anymore, the page was effectively ‘dead’. The confusing part, was that if I used exactly same html, code etc on a page outside of SharePoint I didn’t have any problems at all. This was specifically related to pages hosted within SharePoint.

After digging around I found a comment buried down within a thread (http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/107b2c17-07fe-4a15-ad81-dcb31e1e9c84/#b5295204-c20a-4910-ab4b-d870ac09f687) where the following solution was proposed, and it works a treat:

In the page where your ‘download’ button resides, add the following code where you create the button control:

downloadButton.OnClientClick = “this.form.onsubmit = function() {return true;}”;

If using a LinkButton instead of a Button add the following instead:

exportButton .OnClientClick = “document.getElementsByTagName(\’form\’)[0].onsubmit = function() {return true;}”;

And everything then continues to work when you return to your page. The reason appears to be based on the fact that Sharepoint updates some kind of timestamp hash on the form before it is actually submitted to the server. This is done in order to prevent the form from being submit more than once if the user clicks before the Postback is completed, which is a good thing – except when trying to do what we are trying to do here.