Showing posts with label SharePoint. Show all posts
Showing posts with label SharePoint. Show all posts

Sunday, February 7, 2010

A custom rendering template for the Calendar View control

Q: How do I create a custom rendering template that only affects one calendar view on the site?

A: In Microsoft Office SharePoint Server 2007 and WSS 3.0 it is possible to use a custom view style with the SPCalendarView control, so that additional views or replacements for the default views (Day, Week, Month) can be rendered by a custom RenderingTemplate.

This functionality is provided by using the undocumented SPCustomViewElement element definition, which may be used to create a custom view feature at the web level, that it turn points to the custom rendering template, e.g.:

<?xml version="1.0" encoding="utf-8"?>

<Solution xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SolutionId="453b1767-713e-4ca2-80bb-33aa0b40348e" xmlns="http://schemas.microsoft.com/sharepoint/">

  <FeatureManifests>

    <FeatureManifest Location="HubKey.SharePoint\feature.xml" />

  </FeatureManifests>

</Solution>

<?xml version="1.0" encoding="utf-8" ?>

<Feature  Id="EE647B50-1408-4ac7-9B8F-27D86A2E8985"

          Title="HubKey Calendar View Feature"

          Description="Adds calendar custom view."

          Version="1.0.0.0"

          Creator="http://www.hubkey.com"

          ActivateOnDefault="True"

          Scope="Web"

          xmlns="http://schemas.microsoft.com/sharepoint/">

  <Properties>

    <Property Key="GloballyAvailable" Value="true" />

  </Properties>

    <ElementManifests>

        <ElementManifest Location="elements.xml" />

    </ElementManifests>

</Feature>

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

    <CustomView

        Title="Work Week" 

        Type="workweek" 

        ListType="Events" 

        ListViewType="CALENDAR" 

        Sequence="0" 

        AccessKey="w" 

        ImageHeight="15"

        ImageWidth="15"

        ImageName="week.gif"

        ViewChromeTemplateId="CustomCalendarViewweekChrome">

    </CustomView>

</Elements>



Although this functionality is native to MOSS and WSS 3.0, the definition for SPCustomViewElement may have been omitted from the wss.xsd schema. If this type is missing from the TEMPLATE\XML\wss.xsd file, the addition of a solution with the CustomView element will fail when verified against the schema. To avoid this scenario, the following type definition (highlighted in turquqoise) must be included in the wss schema file. Please note that editing the wss schema file cannot be recommended, please contact your Microsoft representative for more information.

<xs:complexType name="ElementDefinitionCollection">

        <xs:sequence>

            <xs:choice minOccurs="0" maxOccurs="unbounded">

                <xs:element name="ContentType" type="ContentTypeDefinition"/>

                <xs:element name="ContentTypeBinding" type="ContentTypeBindingDefinition"/>

                <xs:element name="DocumentConverter" type="DocumentConverterDefinition"/>

                <xs:element name="FeatureSiteTemplateAssociation" type="FeatureSiteTemplateAssociationDefinition"/>

                <xs:element name="Field" type="SharedFieldDefinition"/>

                <xs:element name="CustomAction" type="CustomActionDefinition"/>

                <xs:element name="CustomActionGroup" type="CustomActionGroupDefinition"/>

                <xs:element name="HideCustomAction" type="HideCustomActionDefinition"/>

                <xs:element name="Module" type="ModuleDefinition"/>

                <xs:element name="ListInstance" type="ListInstanceDefinition"/>

                <xs:element name="ListTemplate" type="ListTemplateDefinition"/>

                <xs:element name="Control" type="DelegateControlDefinition"/>

                <xs:element name="Receivers" type="ReceiverDefinitionCollection"/>

                <xs:element name="Workflow" type="WorkflowDefinition"/>

                <xs:element name="UserMigrator" type="UserMigratorDefinition"/>

                <xs:element name="CustomView" type="CustomViewDefinition"/>

            </xs:choice>

        </xs:sequence>

        <xs:attribute name="Id" type="UniqueIdentifier"/>

    </xs:complexType>

    <xs:complexType name="CustomViewDefinition" mixed="true">

        <xs:attribute name="ViewChromeTemplateId" type="xs:string"/>

        <xs:attribute name="ImageName" type="xs:string"/>

        <xs:attribute name="ImageWidth" type="xs:string"/>

        <xs:attribute name="ImageHeight" type="xs:string"/>

        <xs:attribute name="AccessKey" type="xs:string"/>

        <xs:attribute name="Sequence" type="Sequence"/>

        <xs:attribute name="ListViewType" type="xs:string"/>

        <xs:attribute name="ListType" type="xs:string"/>

        <xs:attribute name="Type" type="xs:string"/>

        <xs:attribute name="Title" type="LocalizableString"/>

    </xs:complexType>



The custom rendering template shown below is copied from the CalendarViewweekChrome template. Use DefaultTabsEnabled=false (highlighted in turquqoise) to replace the default calendar view tabs.

<SharePoint:RenderingTemplate ID="CustomCalendarViewweekChrome" runat="server">

    <Template>

     <div id=CustomWeeklyViewDefault_CalendarView style="display:block; overflow:auto; width:<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ChromeWidth",""))%>; height:<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ChromeHeight",""))%>;"  dir="<%# DataBinder.Eval(Container,"Direction","")%>" >

      <table border=0 width=300 id="CalViewTable1" style="border-collapse: collapse" cellpadding=0>

            <tr><td class="ms-calheader" ><IMG SRC="/_layouts/images/blank.gif" width=742 height=1 alt=""></td></tr>

            <tr>

               <td class="ms-calheader">

               <table border="0" width="100%" cellspacing="1" cellpadding="0" id="CalViewTable12" style="border-collapse: collapse">

                    <tr>

                        <td nowrap>

                            <div class="ms-cal-navheader" nowrap>

                              <a href="javascript:MoveToDate('<%# DataBinder.Eval(Container,"PreviousDate","") %>');" tabindex=1 style="visibility:<%# DataBinder.Eval(Container,"PreviousDateVisible","")%>" accesskey="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_prev_AK%>' EncodeMethod='HtmlEncode'/>" >

                                <img border="0" src="/_layouts/images/prevbutton<%# DataBinder.Eval(Container,"Direction","")%>.gif" width="15" height="15" alt="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_prevweek%>' EncodeMethod='HtmlEncode'/>" ></a>

                              <a href="javascript:MoveToDate('<%# DataBinder.Eval(Container,"NextDate","") %>');" tabindex=1 style="visibility:<%# DataBinder.Eval(Container,"NextDateVisible","")%>" accesskey="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_next_AK%>' EncodeMethod='HtmlEncode'/>">

                                <img border="0" src="/_layouts/images/nextbutton<%# DataBinder.Eval(Container,"Direction","")%>.gif" width="15" height="15" alt="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_nextweek%>' EncodeMethod='HtmlEncode'/>" ></a>

                              &nbsp;<%# DataBinder.Eval(Container,"HeaderDate","") %>&nbsp;

                             </div>

                        </td>

                        <td>&nbsp;</td>

                        <td class="ms-cal-nav-buttons<%# DataBinder.Eval(Container,"Direction","")%>">

                          <Sharepoint:SPCalendarTabs ID="SPCalendarTabs1" runat="server" DefaultTabsEnabled=false

                            SelectedViewTab='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ViewType","")) %>'

                            ListName='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ListName","")) %>'

                            ViewGuid='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ViewName","")) %>'

                          >

                          </Sharepoint:SPCalendarTabs>

                        </>

                    </tr>

                </table>

               </td>

            </tr>

            <tr>

            <td>

                <Sharepoint:WeeklyCalendarView ID="WeeklyCalendarView1" runat="server" IsWorkWeek=true

                    SelectedDate='<%# DataBinder.Eval(Container,"SelectedDate","") %>'

                    ItemTemplateName="CalendarViewWeekItemTemplate"

                    ItemAllDayTemplateName="CalendarViewWeekItemAllDayTemplate"

                    ItemMultiDayTemplateName="CalendarViewWeekItemMultiDayTemplate"

                    TabIndex=2

                >

                </Sharepoint:WeeklyCalendarView>

            </td>

            </tr>

         </table>

    </div>

    </Template>

</SharePoint:RenderingTemplate>



The CalendarViewStyles element in the view’s Schema Xml can be used to set the default view, e.g.:

<CalendarViewStyles>

    <CalendarViewStyle Title=' Work Week' Type='workweek' Template='CustomCalendarViewweekChrome' Sequence='0' Default='TRUE'/>

    <CalendarViewStyle Title='Day' Type='day' Template='CalendarViewdayChrome' Sequence='1' Default='FALSE'/>

    <CalendarViewStyle Title='Week' Type='week' Template='CalendarViewweekChrome' Sequence='2' Default='FALSE'/>

    <CalendarViewStyle Title='Month' Type='month' Template='CalendarViewmonthChrome' Sequence='3' Default='FALSE'/>

</CalendarViewStyles>

Friday, February 6, 2009

SharePoint API: A Client-side Object Model - Demo Application

Back in November we released HubKey's Client-side API for SharePoint. This API wraps many of SharePoint Server 2007's Web Services (Lists Web Service, Webs Web Service, etc.) to provide a familiar object model that can be used on remote client machines without having to process XML requests and responses.

We've recently made a few updates and have included a demonstration application which is shown running in the screen capture below. This demo app creates a new list on a remote test site with a quick launch link, creates a "test person" list scoped content type, adds a number of randomly generated people records, and then adds a new default view with a custom query returning people below age 65. This list data is then browsable and editable by a DataGridView hosted in a Windows form. In addition, paging is demonstrated by using the SPListItemCollectionPosition object.

You can download a demo copy of the API - click here for details.

Monday, December 22, 2008

Get Distinct Lookup Values

Here's another code example using HubKey's Client-side API for SharePoint. In this case 2 lists are created, a document library and a generic list. A lookup field (Subject) is added to the document library which looks up values in the Title column on the second list. The example also demonstrates getting distinct rows (in this case lookup values) by using the DataView.ToTable() method.

using System;
using System.Collections.Generic;
using System.Text;
// using HubKey's Remote SharePoint API instead of the native object model so we can update a remote server
using HubKey.Web.Services.SharePoint;
//using Microsoft.SharePoint;
using System.Data;
 
namespace DevHoleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //always use a test server and site with this beta API
            SPWeb web = new SPSite("http://remoteserver/testsite001/").OpenWeb();
 
            Guid subjectsListId = web.Lists.Add("HubKey Subjects", "A temporary list.", SPListTemplateType.GenericList);
            SPList subjectsList = web.Lists[subjectsListId];
 
            // note that using the SPList.Items property here with the HubKey API returns all the items in the list
            // which can be expensive if the list contains many items already. See the following code example for a 
            // better way to add items to a list specific to the HubKey API:
            // http://www.hubkey.com/Documents/HubKeySPAPI/html/60759825-9963-20e4-c31e-ae93ea608330.htm
            SPListItemCollection subjects = subjectsList.Items;
 
            SPListItem item1 = subjects.Add();
            item1["Title"] = "SharePoint";
            item1.Update();
 
            SPListItem item2 = subjects.Add();
            item2["Title"] = "Microsoft CRM";
            item2.Update();
 
            SPListItem item3 = subjects.Add();
            item3["Title"] = "Microsoft CRM";
            item3.Update();
 
            Guid booksDocLibId = web.Lists.Add("HubKey Books", "A temporary document library.", SPListTemplateType.DocumentLibrary);
            SPList booksDocLib = web.Lists[booksDocLibId];
 
            booksDocLib.Fields.AddLookup("Subject", subjectsListId, false);
            booksDocLib.Update();
            SPFieldLookup subjectLookup = new SPFieldLookup(booksDocLib.Fields, "Subject");
            subjectLookup.LookupField = "Title";
            subjectLookup.Update();
 
            // build the query to get a list of subjects
            // (pretend we are starting from scratch)
            SPFieldLookup subjectLookup2 = (SPFieldLookup)booksDocLib.Fields["Subject"];
            SPList subjectsList2 = web.Lists[new Guid(subjectLookup2.LookupList)];
 
            SPQuery query = new SPQuery();
            query.ViewFields = "<FieldRef Name='" + subjectLookup2.LookupField + "'/>";
 
            // here we use a data table so that we can get distinct titles (subjects)
            // if you're not woried about distinct values you could ignore this, but it's
            // also a convenient way to query the list items (e.g. see the RowFilter below)
            DataTable subjectsTable = subjectsList2.GetItems(query).GetDataTable();
 
            DataView dataView = new DataView(subjectsTable);
            DataTable groupedSubjectsTable = dataView.ToTable(true, "Title");
 
            SPFieldLookupValue lookupValue = null;
 
            // here we're looping through 2 distinct title rows ('SharePoint' and 'Microsoft CRM')
            foreach (DataRow row in groupedSubjectsTable.Rows)
            {
                string title = (string)row[0];
 
                // get the ID of the first row that matches the title
                dataView.RowFilter = "Title = '" + title + "'";
                int firstId = (int)dataView.ToTable(true, "ID").Rows[0][0];
 
                // create a new lookup value (we'll use the 2nd row's lookupValue below)
                lookupValue = new SPFieldLookupValue(string.Format("{0};#{1}", firstId, title));
            }
 
            SPFile file = booksDocLib.RootFolder.Files.Add("test.txt", Encoding.ASCII.GetBytes("A test document."));
 
            // update the subject with the 2nd lookup value;
            file.Item["Subject"] = lookupValue;
            file.Item.Update();
 
            // clean up - pause here if you want to view the results on the server.
            subjectsList.Delete();
            booksDocLib.Delete();
 
        }
    }
}