SharePoint 2010: Lists.GetListItemChangesWithKnowledge Method

SharePoint 2010 has its own sync provider built in which is consumed by other client applications such as SharePoint Workspace 2010. You can read the case study here.

 

Microsoft Uses Sync Framework to Create New Collaboration Solution

As Microsoft, the world leader in software for personal and business computing, prepared the next version of its Microsoft® Office suite of desktop applications it wanted to combine the functionality of two of its most popular collaboration tools: Microsoft SharePoint® Server and Microsoft Groove®. The company’s development teams, however, faced the challenge of handling data synchronization to ensure version control. They found the technology they needed with the Microsoft Sync Framework, a technology developed by the Microsoft Sync Framework group, which is part of the Microsoft SQL Azure™ team. The result is Microsoft SharePoint Workspace 2010, which provides the rich user experience of a desktop application, with the Sync Framework handling data synchronization with sites created using SharePoint Server 2010.

 

As a developer if you want to make use of this in-built sync framework to build your SharePoint client applications, you can do so! Let me introduce to the new Lists.asmx method: GetListItemChangesWithKnowledge. This method returns all of the list items that meet specified criteria and that have changed since the date-time specified in the knowledge parameter for the specified list. You can read this blog post to know more about the sync knowledge.

 

GetListItemChangesWithKnowledge Usage:

 

To use this method, you need to add reference to the Lists.asmx web service to your application: http://<site-name>/_vti_bin/Lists.asmx

 

After that you can use the method as follows:

 

using (Lists list = new Lists())
{
  list.Credentials = new NetworkCredential("username", "password", "domain");

  changedItems = listTLA.GetListItemChangesWithKnowledge("Projects", null, null, null, 
                                                          null, null, null, null, null);
}

 

You can pass null for every parameter except for the first one which is the name of the list. As you can see we are passing null for the sync knowledge too. Initially, we can pass to get all the items (which are new). The method will also return the sync knowledge which then you can use for the subsequent calls. Below is an example of what we get back the first time:

 

<Changes xmlns="http://schemas.microsoft.com/sharepoint/soap/">
    <MadeWithKnowledge>
        <sync:syncKnowledge xmlns=http://schemas.microsoft.com/2008/03/sync/ 
                             xmlns:sync="http://schemas.microsoft.com/2008/03/sync/">
            <idFormatGroup>
                <replicaIdFormat sync:isVariable="false" sync:maxLength="16" />
                <itemIdFormat sync:isVariable="false" sync:maxLength="16" />
                <changeUnitIdFormat sync:isVariable="false" sync:maxLength="1" />
            </idFormatGroup>
            <replicaKeyMap>
                <replicaKeyMapEntry sync:replicaId="jeJVN1EeT3Sn+NBWZOmqoA==" sync:replicaKey="0" />
            </replicaKeyMap>
            <clockVector>
                <clockVectorElement sync:replicaKey="0" sync:tickCount="1589" />
            </clockVector>
        </sync:syncKnowledge>
    </MadeWithKnowledge>
</Changes>
<rs:data ItemCount="1" xmlns:rs="urn:schemas-microsoft-com:rowset">
    <z:row ows_Attachments="0" 
           ows_LinkTitle="Kim Abercrombie" 
           ows_JobTitle="Test Lead" 
           ows_Team="AP" 
           ows_Contribution_x0020__x0028_in_x00="2.00000000000000" 
           ows_Project="1;#Writing more sample code" 
           ows__ModerationStatus="0" 
           ows__Level="1" 
           ows_Title="Kim Abercrombie" 
           ows_ID="1" 
           ows_UniqueId="1;#{92367B48-BF4E-4EB7-A653-EDD777CE4612}" 
           ows_owshiddenversion="1" 
           ows_FSObjType="1;#0" 
           ows_Created_x0020_Date="1;#2010-03-15T01:13:36Z" 
           ows_Created="2010-03-15T01:13:36Z" 
           ows_FileLeafRef="1;#1_.000" 
           ows_PermMask="0x7fffffffffffffff" 
           ows_Modified="2010-03-15T01:13:36Z" 
           ows_FileRef="1;#Lists/Employees/1_.000" 
           ows_MetaInfo="1;#" 
           ows_ServerRedirected="0" 
           xmlns:z="#RowsetSchema" />
    
</rs:data>

 

As you can see, the sync knowledge associated is the sync:syncKnowledge parameter. You can use this parameter from now on to get updates on this list by passing it into the GetListItemChangesWithKnowledge method.

 

If you had a delete, the returned XML will look like:

 

<Changes ServerTime="20100421 10:35:49">
    <Id ChangeType="Delete" ServerChangeUnit="{E5C5E20A-5A9F-406C-B9F6-28923750CECD}:3510" 
                               UniqueId="{94512989-20A7-4BF3-9C13-AEB8BADD1F7C}">4</Id>
        <MadeWithKnowledge>
            <sync:syncKnowledge xmlns=http://schemas.microsoft.com/2008/03/sync/ 
                               xmlns:sync="http://schemas.microsoft.com/2008/03/sync/">

 

You can get the Delete event under the Changes parameter.

 

In the coming weeks, I will be blogging on building a SharePoint 2010 sync client application using the GetListItemChangesWithKnowledge method.

SharePoint 2010 List Validation Formulas

SP2010 Validation Formulas

Earlier, I wrote a post on Column Validation and List Validation settings in SharePoint 2010. If you are wondering where to get help for the currently supported formulas for SharePoint 2010 beta 2, then here is the ‘precious’ link for you - http://bit.ly/sp2010-formulas

 

If you are still stuck with any of the formulas, feel free to discuss it at the SharePoint 2010 MSDN Forums

SharePoint 2010 List Improvements – Column Validation and List Validation Settings

Another great improvement in SharePoint 2010 is that now you can specify formulas that validate the columns based on other columns!

Let me take you through an example.

Here is a simple list called Scores

Scores List

It stores the student scores for Paper 1 – Paper 5 , total score and the result. The scores are values between 1 to 100.

[ This is still doable without any formulas by setting the maximum and minimum values for the Number column. But I am using this example to illustrate the Column Validation. But there is still one advantage of using validation than using the maximum and minimum setting :) ]

Let us add a new item:

Ad dnew Score item

Looking at it, it is obvious that Paper 2 has a score of 150 and is invalid. So, we should be showing some error messages so that users get notified that the information entered is invalid.

Column Validation

In SharePoint, now columns have a new section called Column Validation where you can enter formulas (similar to Excel formulas) to pass validation.

Column Validation

You can enter the formula and the corresponding message that you want to display to the users if the validation fails. [You can customize the error message the way you want if you this validation than using the maximum and minimum settings :) ]

The formula is pretty similar to Excel. I also remember seeing some SharePoint functions (in the early builds), but the help is currently unavailable so we have to wait till the public beta is released.

Remember, this is a column validation and not list validation, so if its created at the site level, it will apply everywhere.

List Validation

You can do the same thing at the list level. You can access this in the List settings page:

List Validation Settings

List Validation

The only difference is now you know what are the columns you would be validating against.

Validation in action

Here is validation in action:

Validation in action

Notice how it changes the focus and also displays the error message below that particular column.

Validation via code

For the developers out there, here is how you can set the validation formula and message via object model:

using (SPSite spSite = new SPSite("http://site"))
{
using (SPWeb spWeb = spSite.RootWeb)
{
SPList lstScores = spWeb.Lists.TryGetList("Scores");

if (lstScores != null)
{
SPFieldNumber fldPaper1 =
lstScores.Fields.GetField("Paper 1") as SPFieldNumber;
fldPaper1.ValidationFormula =
"=AND([Paper 1]<=100,[Paper 1]>0)";
fldPaper1.ValidationMessage =
"Invalid score entered. Please enter a value between 1-100.";
fldPaper1.Update();
}
}
}
 
Note: Lists.TryGetList is a new method which you can safely use to get a SPList object. If the list doesn’t exists, it returns null.

SharePoint 2010 Lists Improvements – List Lookups and Relationships

SharePoint 2010 brings in quite a few changes to Lists in SharePoint, especially in the lookup columns and enforcing relationships.

When you create a Lookup Column in SharePoint 2010 which fetches data from another List’s field, you can now add additional lookup fields and not just the identifier field!

image 

Along with adding additional lookup fields, you can also enforce relationships so that it allows a cascade delete or restricts delete if a relationship still exists:

image

So, if there is a relationship associated, then you get this lovely error message when you try to delete an item (relationship behaviour configured to Restrict delete):

image

A Powerful Example to showcase List Relationships

Well, there isn’t much if I just show you the new options in lookup fields and relationships. Here is an example to show how powerful the relationships are in SharePoint 2010!

Projects and Employees List

So, I have two lists Projects and Employees list:

image

image

As you can see the Projects list has a lookup field Primary Contact which links to the Employees Fullname field. And the Employees list has a lookup field Project referring to the Project Title field.

If you click on a Project item, you get to see the project details, which is obvious:

image

Now, I would also like to see all the employees associated with this project. Given that we already have linked Projects and Employees list, this is certainly doable. You would go about asking any of your developers to build a web part that would do this job. With SharePoint 2010, its just plain simple with few steps :)

All we need to do is edit the default display form and add the Employees list!

In the SharePoint Ribbon (when you are on the List page, click on List in the Ribbon), select to edit the default display form:

image

This is the form that displays when you view an item.

This will open the default display form page in edit mode. Notice that the Ribbon now has Insert tab. Click on Insert and you will find the Related List button!

image

You can see the Employees list listed there! As it says, inserting this related lists web part will display related Employees items based on the Project lookup column! Go ahead and insert the list:

Below is the display form page with the related list web part added:

image

Save the page, and now, clicking on a Project item, you can see all the Employees associated with that particular project!

image

That wasn’t hard! Now, this is what I call a ‘killer-feature!’ :)

Using same custom edit forms across different Lists in SharePoint

We have a customer who has 5 different Lists and all the Lists have same content type associated with it. They wanted a custom edit form for this content type and want to use it across those 5 different Lists to enter data. We created the custom edit form very easily and uploaded the form to the Layouts folder (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS) so that we can load it in the code-behind.

The problem arose when we wanted to use the same custom edit form across different List as these custom edit forms are bound to a specific List

<ParameterBindings>
            <ParameterBinding Name="ListItemId" Location="QueryString(ID)" DefaultValue="0"/>
            <ParameterBinding Name="ListID" Location="None" 
                     DefaultValue="{7A0F7220-4967-4061-985D-D78F4435B071}"/>
            <ParameterBinding Name="dvt_apos" Location="Postback;Connection"/>
            <ParameterBinding Name="UserID" Location="CAMLVariable" DefaultValue="CurrentUserName"/>
            <ParameterBinding Name="Today" Location="CAMLVariable" DefaultValue="CurrentDate"/>
</ParameterBindings>

 

As you can see in the above snippet, it is clearly bound to a List with ID {7A0F7220-4967-4061-985D-D78F4435B071}

So, how can you associate this custom edit form to work across a different List? I don't want to create x-number of forms for x-number of Lists!

Well, out of luck, we actually figured it out how to do so! – Setting the DefaultValue of the ListID to 0

If you put 0 instead of the List ID, it automagically identifies the List that the form is bound to during runtime and works like a charm!

So, here is my XML schema after the change:

<ParameterBindings>
            <ParameterBinding Name="ListItemId" Location="QueryString(ID)" DefaultValue="0"/>
            <ParameterBinding Name="ListID" Location="None" DefaultValue="0"/>
            <ParameterBinding Name="dvt_apos" Location="Postback;Connection"/>
            <ParameterBinding Name="UserID" Location="CAMLVariable" DefaultValue="CurrentUserName"/>
            <ParameterBinding Name="Today" Location="CAMLVariable" DefaultValue="CurrentDate"/>
</ParameterBindings>

Its weird, but true :)


Creative Commons License
Chaks' Corner Blog by Chakkaradeep Chandran is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.
Based on a work at www.chakkaradeep.com.
Permissions beyond the scope of this license may be available at http://www.chakkaradeep.com.