Tuesday, May 29, 2007

Using Parameters in the SelectCommand of a Data View Web Part

The SelectCommand attribute of the SPDataSource element within a SharePoint DataView web part can use parameters supplied to the web part - and these parameters can come from a varity of sources, including the querystring in the page request.

This opens the way to easily control the data displayed in the data view; for example, via an ID supplied in the querystring.

The following code snippet shows some of the DataFormWebPart elements that use a value in the querystring to select a single list item to be displayed (the parameter is named SelectedRisk). Notice how the parameter is referenced in the SelectCommand:

<DataSources>

    
<SharePoint:SPDataSource runat="server" SelectCommand="<View><Query><Where><Eq><FieldRef Name="ID"/><Value Type="Counter">{SelectedRisk}</Value></Eq></Where></Query></View>" ...>

        
<SelectParameters>

            
<WebPartPages:DataFormParameter PropertyName="ParameterValues" ParameterKey="SelectedRisk" DefaultValue="0" Name="SelectedRisk"></WebPartPages:DataFormParameter>

        
</SelectParameters>

    
</SharePoint:SPDataSource>

</DataSources>

<ParameterBindings>

    
<ParameterBinding Name="SelectedRisk" Location="QueryString(ID)" DefaultValue="0"/>

</
ParameterBindings>

Querying in CAML Relative to Today's Date

Found little information when searching for ways to perform date queries using CAML relative to today's date - only one reference to the use of OffsetDays from the article Customise the Content Query Web Part . Surprising the lack of information on this technique.

Here's the example from that article:

<Where>
  
<Gt>
      <FieldRef Name="Created" Nullable="True" Type="DateTime"/>
      <
Value Type="DateTime"><Today OffsetDays="-7"/></Value>
  
</Gt>
</Where>

Simple script to Remove and Redeploy a Feature

This script deactivates and deletes an existing feature, then redeploys this feature - it is useful when modifying features during development:


REM Add the 12 Hive bin folder to the path for access to STSADM
@set PATH=C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN;%PATH%

REM Configure local values
set siteURL=[site URL here]
set featureName=[Name of the feature]
set WSP=[Name of the WSP file, including the WSP extension]

REM Go to the folder containing the WSP file
cd [Full path to the folder holding the WSP file]

REM Remove the solution
stsadm -o deactivatefeature -name %featureName% -url %siteURL% -force
stsadm -o retractsolution -name %WSP% -immediate
stsadm -o execadmsvcjobs
stsadm -o deletesolution -name %WSP% -override
stsadm -o execadmsvcjobs

REM Add the solution
stsadm -o addsolution -filename %WSP%
stsadm -o execadmsvcjobs
stsadm -o deploysolution -name %WSP% -immediate -allowgacdeployment
stsadm -o execadmsvcjobs
stsadm -o activatefeature -name %featureName% -url %siteURL% -force

Sunday, May 20, 2007

Changing the URL of a SharePoint Site Collection

Noticed that a site collection had a poor URL - to change the URL, backup the site and then restore using stsadm command-line operations:

To backUp:
stsadm -o backup -url {existing site collection URL} -filename {name of file}

To restore:
stsadm -o restore -url {new site collection url} -filename {name of file}

Thanks to Jose Barreto for saving me the task of rebuilding the collection from scratch

Thursday, May 10, 2007

Getting Users from Multi-select Person or Group Fields

The following code illustrates how to extract user information for all users listed in a multiselect Person or Group field (in this case extracting all the users listed in the "Control Owners" field of the first list item in the "Controls" list) :

using (SPWeb web = new SPSite(WEB_URL).OpenWeb())
{
    StringBuilder sb 
= new StringBuilder();    
    
SPList list web.Lists["Controls"];

    
SPFieldUserValueCollection userVals (SPFieldUserValueCollection)list.Items[0]["Control Owners"];
    foreach 
(SPFieldUserValue userVal in userVals)
    {        SPUser user 
userVal.User;
          
sb.AppendLine(string.Format("{0}", user.LoginName));
    
}
}

Wednesday, May 9, 2007

Starting From Scratch

Spent a few interesting hours today working with Dave Mateer and Michael Smithson on a new web application for Treasure Hunts in Christchurch.

The idea behind this project of Dave's is to explore topics like scrum, architecture, enterprise library, asp.net drag-and-drop controls by developing an actual web application - far more likely to learn useful stuff when the target is an actual live application than just by "playing" with the technologies.

We made a good start this morning, discussing stories for the application and spiking a tiered architectured. Found the hosting at www.openhost.co.nz to be very usable. Slotted the Enterprise Library v3 into the solution to gain easy DAL access to the database (and to get re-acquainted with it's strengths).

We cut the initial code using pair programming - I've never tried this technique properly before, and found that once over the initial discomfort of having my poor typing skills scrutinised (you know the feeling? Spelling and keyboard skills disappear as soon as someone is watching over your shoulder!), it was good to have improvements pointed out as the lines of code grew. Maybe one day AI will reach the stage that our PCs can make verbal suggestions as they "watch" what we type - though then again that's a worrying thought.

Dave, Michael and others are to continue working on the application until Sunday afternoon. Good luck, guys! I reckon it will be a useful little application when finished - I certainly plan to do one of the treasure hunts with my family.

Dave is blogging about the experience at http://treasuresprint.blogspot.com/

Tuesday, May 8, 2007

SharePoint ListTemplate IDs

Here are the SharePoint 2007 ListTemplateIDs for use in event receivers (amongst others!):
List Template IDList Type
100Generic (custom) List
101Document Library
102Survey
103Links List
104Announcements
105Contacts
106Events
107Tasks
108Discussion Board
109Picture Library
110Data Source
111Site Template Gallery
113Web Part Gallery
114List Template Gallery
115Form Library
119Wiki Page Library
120Generic (custom) List in Datasheet view
150Project Tasks
200Meeting Series List
201Meeting Agenda List
202Meeting Attendees List
204Meeting Decision List
207Meeting Objectives List
211Meeting Things to Bring List
212Meeting Workspace Pages List
300Portal Sites List
1100Issue Tracking

The LCID and FormatFlag in the ddwrt:FormatDate method

The following images illustrate the date strings output by setting the LCID and FormatFlag parameters in the ddwrt:FormatDate(szDate, lcid, FormatFlag) method. Note that the use of an LCID of 1053 and a FormatFlag of 5 gives a sortable string value.

I have added the code used to generate these lists in this post.

en-US (LCID 1033)

de-DE (LCID 1031)

es-ES (LCID 1034)

en-GB (LCID 2057)

Adding Custom Build Steps to a Visual Studio Project

Developing a solution to deploy a timer job involves modifying the CSPROJ file (an MSbuild file) to call the MakeCab utility - this creates a WSP file.

I found that adding an Import statement referring to the custom Targets file (in this case named BuildSharePointPackage.targets) from within the CSPROJ file didn't always produce the right output.

The cause was that MSBuild executes the last build target in order of appearance of Import statements. The csproj file included:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<
Import Project="BuildSharePointPackage.targets" />

The BuildSharePointPackage.targets file did not call any of the standard compile statements in the Microsoft.CSharp.targets file used to build C# projects, so the dlls were not getting rebuilt, and old versions os the dlls were being placed in the WSP file.

The solution was as follows:
  1. Set the DefaultTargets attribute in the Project element of the csproj file to equal the Name attribute of the Target element in the custom targets file:
    <Project DefaultTargets="BuildMossPlus" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  2. Add a DependsOnTarget attribute to the Target element in "BuildSharePointPackage.targets":

    <?xml version="1.0" encoding="utf-8" ?>
    <Project DefaultTargets="BuildMossPlus" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      
    <PropertyGroup>
        
    <MakeCabPath>"C:\Program Files\Microsoft Cabinet SDK\BIN\MAKECAB.EXE"</MakeCabPath>
      </PropertyGroup>
      
    <Target Name="BuildMossPlus" DependsOnTargets="$(BuildDependsOn)">
        
    <Exec Command="(SOME COMMAND)"/>
      </
    Target>
    </Project>


(with help from the MSBuild Team Blog)

SPSchedule String Formats (the FromString method)

When establishing timer jobs by defining an SPSchedule in a feature receiver (as per Andrew Connell's excellent article), the schedule can be entered using the FromString method of the SPSchedule class - see this post by Mark Arend for the acceptable string formats.

Note that this is a static method!

There is a lot of choice and flexibility in the permitted formats - some examples are "every 15 minutes", "hourly between 10 and 12" and "monthly at 1 09:00:00"

Tuesday, May 1, 2007

Connecting to Two Web Parts with a Different Parameter for Each

Had a solution requiring a single drop-down list in a dataview web part to filter the contents of two other data view web parts, each of which required a different field as the input parameter - i.e. the Controls web part was to be filtered by Control Refs and the Gaps web parts was to be filtered by Gap Refs. The two fields (Control Refs and Gap Refs) are multi-select lookup columns in the Risks list.

After much experimentation (and a fair bit of cursing!), I found the answer.

The dropdown dataview uses the following code for each row. The important points to note are the concatenation of the two required field values in the fields variable, and the concatenation of the two consumer GUIDs in the GenFireCOnnection call.

<option>
    
<xsl:attribute name="value">
        
<xsl:variable name="cursel">dvt_curselkey={<xsl:call-template name="dvt.gencurselkey"><xsl:with-param name="RowPath" select="." /></xsl:call-template>}</xsl:variable>
        
<xsl:variable name="fields">@Control_x0020_Refs=<xsl:value-of select="ddwrt:ConnEncode(string(@Control_x0020_Refs))" />#@Gap_x0020_Refs0=<xsl:value-of select="ddwrt:ConnEncode(string(@Gap_x0020_Refs0))" /></xsl:variable>
        
<xsl:text>javascript:</xsl:text>
        
<xsl:value-of select="ddwrt:GenFireConnection( concat( 'g_1a7694bc_1a99_427e_aece_bcbfdf0ba2b9#g_c79865fa_2833_4543_aefe_0a8f466211aa*', $fields),string($cursel))"></xsl:value-of>
        
<xsl:text>;</xsl:text>
    
</xsl:attribute>
    
<xsl:if test="$dvt_curselkey=@ID">
        
<xsl:attribute name="selected">true</xsl:attribute>
    
</xsl:if>
    
<xsl:value-of select="@Risk_x0020_Ref" /> - <xsl:value-of select="@Title" />
</
option>

Data Source Details in SharePoint Designer Fails to Show List Data

I have a list with a calculated value which is based on two other text values. Having entered a few test items in the list, the Data Source Details pane in SharePoint Designer was reporting an error with retrieving data for that list.

Further investigation revealed that one of the paths through the formula for the calculated column was returning a number rather than a string. This incorrect data type was causing the failure in the Data Source Details