Aug
20
2008

SPRegionalSettings.GlobalTimeZones - How to build world clock / get time zones information in SharePoint

Ok, you probably do not want to create world clock web part from scratch. Many free ones over Internet. Not to mention the very popular world clock web part from "bamboo Solutions".

But if you really want to create one by yourself for whatever the reason is, or you just want show the local time for employees working in different cities around the world (in their profile page, maybe). It can be done easily without to use any external web services, or hack your way through windows registry to get time zones list.

Yes, thanks to SharePoint OM. You can get all the information you want from Microsoft.SharePoint.dll

SPRegionalSettings.GlobalTimeZones

It returns you a collection of SPTimeZones objects used in Windows SharePoint Services.

SPTimeZoneCollection timeZoneColl = SPRegionalSettings.GlobalTimeZones;
foreach (SPTimeZone tz in timeZoneColl)
{
    DateTime currentLocalDateTime = DateTime.Now;
    DateTime currentDestDateTime = tz.UTCToLocalTime(currentLocalDateTime.ToUniversalTime());
        Console.WriteLine("ID: {0}, DateTime: {1}, Description: {2}", tz.ID, currentDestDateTime.ToString(), tz.Description);
}

In above code sample, it loop through each SPTimeZone inside SPTimeZoneCollection. Writes ID, current date time (in local server date time format) and description in console.

This is what you will get

James Tsai .Net SharePoint VSTO C# ASP.NET Blog - SPRegionalSettings GlobalTimeZones Code Sample

As you can see, my local time in Sydney, Australia is Thursday, August 21, 2008 4:01pm. And time in Tokyo, Japan is 08/21/2008 3:01pm. In Auckland, New Zealand is 08/21/2008 6:01pm. Which are correct!

//This line of code converts SPTimeZone object from UTC to your local time
DateTime currentDestDateTime = tz.UTCToLocalTime(currentLocalDateTime.ToUniversalTime());

Basically that's all you need to create world clock web part, or date time conversion control in SharePoint site. You can either have GlobalTimeZones collection as drop down list for user to select the time zone for displaying date time. Or you can create a SharePoint list mapping between cities name with time zone ID in GolbalTimeZones collection.

Aug
12
2008

How to query cross-site lists in DataFormWebPart - Part 3. Filtering on column headers problem

Here are the links to previous two parts of the series

Part 1. Build your own data source for Data Form Web Part

Part 2. Use XSLT generated from SharePoint Designer to display data 

If you build a Data Form Web Part with customized data source (i.e. data source that does cross-sites querying), you've probably noticed the filtering on column headers does not work. In this part of customize Data Form Web Part series, you will see how this problem can be fixed by extend your custom Data Form Web Part code a bit more.

Before click on "Form Name" column header, there are two items displayed under it.

James Tsai .Net Blog - SharePoint C# ASP.NET VSTO -  Data Form Web Part with cross-sites query data source displayed

After click on "Form Name" column header, no available filter data returned.

James Tsai .Net Blog - SharePoint C# ASP.NET VSTO -  Cross-sites query data source with filtering on column headers problem

The Problem

Before we going into how to fix it. You must first understand what is causing this problem. And the answer simple. Because with the customized data source you just created, the original Data From Web Part methods that used to handle filtering are no longer to be able to perform filtering and render filter value correctly.

You will see how it works behind the scene from the following three methods. These methods are called after you clicked on any filterable column header.


/*Microsoft.SharePoint.WebPartPages.DataFormWebPart*/
protected virtual void RaiseCallBackEvent(string eventArgument){};
protected virtual string GetCallbackResult(){};
private string DoCallBackFilters(string filterStr){};

 

RaiseCallBackEvent

This method assigns event argument to the web part (Data Form Web Part in this example) after callback event has been raised.

Event argument is a string variable represent in following format: (i.e. clicked on "Title" column header)

"__filter={Form Name @FormName x:string;1033 g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb}"

As you can see, it contains column name and web part ClientID - g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb.

 

GetCallbackResult

After RaiseCallBackEvent, this method gets called. It first check if raised callback event is for filtering event on column headers. If so, it strips out the filtering string

"Form Name @FormName x:string;1033 g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb"

And pass it to DoCallBackFilters as an input argument.

 

DoCallBackFilters

DoCallBackFIlters prepares callback result that will be used for rendering filtering drop down list on column header. The correct returned string should look like this:

<SELECT>
<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=##dvt_all##}')"></OPTION>
<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=Temp page}')">Temp page</OPTION>
<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=Test Page}')">Test Page</OPTION>
</SELECT>

Note! This is where you get empty result when you clicked on column header. Because this method cannot process your customized cross-sites query data source, it returned empty string instead to GetCallbackResult.
James Tsai .Net Blog - SharePoint C# ASP.NET VSTO -  GetCallbackResult method failed on return correct data

 

Solution

DoCallBackFilters is a private method and there is no way to extend it to make it work the way you wanted. The only option here is to override GetCallbackResult method and make it to call new DoCallbackFilters replacement method. (CustomizedDoCallBackFIlters in this example)

/*Original implementation of GetCallbackResult*/

public virtual string GetCallbackResult()
{
    if (string.Compare(this.eventArgument, 0, "__filter", 0, 8, false, CultureInfo.InvariantCulture) != 0)
    {
        return string.Empty;
    }
    string filterStr = this.eventArgument.Substring(10, this.eventArgument.Length - 11);
    return this.DoCallBackFilters(filterStr);
}

Override above method with following implementation.


/*Override implementation of GetCallbackResult*/
public virtual string GetCallbackResult()
{
    //This is where it make sure event raised from filtering on column headers
    if (string.Compare(this.eventArgument, 0, "__filter", 0, 8, false, CultureInfo.InvariantCulture) != 0)
    {
        return string.Empty;
    }
    string filterStr = this.eventArgument.Substring(10, this.eventArgument.Length - 11);
    return this.CustomizedDoCallBackFilters(filterStr);
}
private string CustomizedDoCallBackFilters(string filterStr)
{
    string yourDataAsString;
    //Build your customized filtering data here. To return data in format described above
    return yourDataAsString;
}

Inside CustomizedDoCallBackFilters method you can build result data with any logic you like. As long as it is in correct format. I suggest you to follow the same logic of how you've built your data source. To make sure data displayed in column headers always consistent with actual displayed items in Data From Web Part.

James Tsai .Net Blog - SharePoint C# ASP.NET VSTO -  Correct data returned from GetCallbackResult method 

More Details

I will explain what should your final result data look like. As you can see in above, it follows this format:


<SELECT>

<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=##dvt_all##}')"></OPTION>

<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=Temp page}')">Temp page</OPTION>

<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=Test Page}')">Test Page</OPTION>

</SELECT>

Each <OPTION/> element inside <SELECT/> has only one attribute "herf". Except first <OPTION/> element served special purpose and I will explain it later.

But first let's see the break down to the "herf" attribute value

James Tsai .Net Blog - SharePoint C# ASP.NET VSTO - Correct result format explained

Only difference in each line are the values used to display on the UI drop down list and used for filtering PostBack result.

The first <OPTION/> is used to indicate whether filtering has been done on current column. To toggle the flag you just need to assign 1 to this <OPTION/> element


<OPTION href="__doPostBack('g_548009f0_beeb_4e3c_a4a6_71fc338cc8cb','NotUTF8;__filter={@FormName=##dvt_all##}')">1</OPTION>

James Tsai .Net Blog - SharePoint C# ASP.NET VSTO - How to use first element in returned result to toggle filtering on column header flag

 

 

That's all. It is pretty much how you fix filtering on column header problem. Just remember to return your final result data in GetCallbackResult().

In summary.

1. Get Callback argument with all the necessary data (field name and control client id).

2. Use above input argument to build result data using any code logic you like.

3. return data in GetCallbackResult() method.

Hope this post helps you to get what you want.

 

James

Aug
10
2008

In Memory of - Lee Marriage 1982 - 2008

Lee Marriage - a colleague of mine passed away yesterday while competing in City to Surf. (News here).

He was SharePoint Technical Lead for the project I am currently working on. A friend, true leader and SharePoint Guru.

Sure it is loss to SharePoint Community, especially he was the one who has helped to organize Sydney SharePoint User Group each month.

I know I am going to miss your UK accent, your joke and your smiley face everyday when I walk in office to work.

Thank you for buying me coffee last week after both you and I returned from leaves to work. I've learnt a lot from you (Drinking is one of them)