Oct
27
2008

How To Create AJAX-enabled SharePoint Web Part with UpdatePanel and UpdateProgress in 10 minutes

In this post I am going to show you how you can setup your SharePoint site to support Microsoft ASP.NET AJAX framework and create a basic AJAX-enabled SharePoint Web Part. You can find many great articles on MSDN on how to do these and they explained in more details, but if you are looking for a way to get it up and running in 10 minutes, this is it.

James Tsai .NET SharePoint Blog - AJAX enabled webpart 

James Tsai .Net SharePoint Blog - AJAX enabled webpart updating

An AJAX-enabled web part with update button and display current time every time when button is clicked. Loading image and text displayed during the update.

Goal

  • Enabling SharePoint site with ASP.NET AJAX framework support
  • Create AJAX-enabled SharePoint web part
    • with UpdateProgress control for visual feedback in browser when web part is updating
    • with AJAX request event script to hide UpdatePanel while web part is updating
  • Add AJAX-enabled web part to page and see it in action

More...

Oct
9
2008

How to change SharePoint Calendar default start hour and end hour of Day View

Default Day View of SharePoint Calendar control has its start hour set to 7am and end hour to 5pm.

James Tsai .Net SharePoint Blog - Default Day View Start Hour

To change this you'll need to update SPRegionalSettings.WorkDayStartHour and SPRegionalSettings.WorkDayEndtHour properties. And it is not something you can do from UI.

For example, to change start hour to 6am and end hour to 6pm you'll have to write and run this code

using (SPSite site = new SPSite("http://<YourSiteUrl>"))
{
    using (SPWeb web = site.RootWeb)
    {
        SPRegionalSettings regionalSettings = web.RegionalSettings;
        regionalSettings.WorkDayStartHour = 360;
        regionalSettings.WorkDayEndHour = 1080;
        web.Update();                  
    }
}

 

The possible values you can set for WorkDayStartHour and WorkDayEndHour are 60 x (hour value in 24 hour format).

Basically, they are total number of minutes. For example,

6am = 6 x 60 = 360

6pm = 18 x 60 = 1080

9pm = 21 x 60 = 1260 and so on..

As you can see, the start hour of Day View in calendar has now changed

James Tsai .Net SharePoint Blog - Changed Day View Start Hour

Hope it helps

-James

Oct
6
2008

How to use SharePoint Delegate Control to change the navigate URL of Manage Links (My Links)

Microsoft Office Online -

By using the My Links menu, you can easily add new links, reorganize your links, access sites where you are a member, and click links to save them to you My Links list.

You can use this feature when you have "My Site" setup and running in your SharePoint Shared Services.

James Tsai .NET SharePoint Blog - My Links Manage Links menu control

Problem

Let's say you have following two site collections setup for your SharePoint intranet site and My Site.

Intranet - http://intranet/

My Site - http://mysite/

When user is accessing manage links page by clicking on My Links, Manage Links menu on Intranet site, the menu control redirects user to

http://mysite/_layouts/MyQuickLinks.aspx

And you probably don't want this to happen, because of following reasons

  • You want to hide My Site from user, but you still want to use My Links feature.
  • You don't want user to navigate away from current site collection when they clicked on the Manage Links menu.
  • You want MyQuickLinks.aspx page to inherit and use current site theme.
  • You are experiencing the MOSS SP1 bug I described in last post.
  • OR you just want to customize it to navigate to the any URL

Goal

The goal here is obvious. To customize the navigate URL of Manage Links. In the example above, user should be redirected to

http://intranet/_layout/MyQuickLinks.aspx

Solution

You'll need following three things to achieve the goal

More...

Sep
26
2008

SharePoint Data View / Data Form Web Part - Group items by month on DateTime field

This is one of the most popular requirements I always get from clients. Especially when they have large collection of documents and want to give their user an easy way to browse document items in Data Form Web Part (DFWP).

For example, you have a list of documents displayed in DFWP and each document has "Published Date" field. How can you group DFWP items by its "Published Date" month value?

Goal

James Tsai .Net SharePoint Blog - DFWP Group By Month Final

Solution

Luckily, all you need to do is to change a few lines in XSL that renders your DFWP. Here is step by step of how to do it.

1. Add "Group By" to Data Form Web Part.

Here is what your original DFWP should look like without any "Group by" on field

James Tsai .Net SharePoint Blog - DFWP default view without Group by field

In SharePoint Designer (SPD), open DFWP's Common Data View Tasks and select "Sort and Group"

James Tsai .Net SharePoint Blog - DFWP common data view tasks

Select DateTime field you want to Group by, In this example it is "Published Date". "Show group header" is also selected here because this way you can see what values are used to group items

James Tsai .Net SharePoint Blog - DFWP sort and group options

After above steps, you can see the DFWP is correctly grouped on "Published Date" field. But it treats each DateTime value as a different group value.

By default, DFWP group DateTime field based on their actual Date (YYYY-MM-DD) value. Not just year and month (YYYY-MM).

James Tsai .Net SharePoint Blog - DFWP Group By DateTime Field Default

Since requirement here is to group items with same month (item with "Publsihed Date" 08/16/2008 and 08/03/2008 in this example) in same group. Further steps are needed.

2. Modify XSL

Inside the XSL that renders your DFWP, search for "dvt_groupfield". If you use "Search All" within XSL, <xsl:when test="not ($dvt_groupfield)"> is the line you want.

James Tsai .Net SharePoint Blog - DFWP XSL Search For DVT_GroupField

And you will see this section,


<xsl:when test="not ($dvt_groupfield)">
        <xsl:value-of select="ddwrt:NameChanged(string(@PublishedDate), 0)" />
</xsl:when>

Change this to,


<xsl:when test="not ($dvt_groupfield)">
        <xsl:value-of select="ddwrt:NameChanged(string(substring(@PublishedDate,1,7)), 0)" />
</xsl:when>

Above change is critical, that's where you specify how you want to group items in DFWP.

The original @PublishedDate value is presented in format "YYYY-MM-DDTHH:MM:SSZ". substring(@PusblishedDate,1,7) gives us "YYYY-MM" which is what we want DFWP to group by. Note: In XSL, index starts from 1 not 0.

You will see this after above changes

James Tsai .Net SharePoint Blog - DFWP XSL After Change Group By Value

Items are now group correctly, but group header still displaying incorrect text. Because In DFWP XSL, group value and header value are generated from different template. You have changed first one (in above step), and now last step is to change header value.

Just scroll down from where you changed group value in XSL a bit, and you should see this line


<xsl:when test="not (@PublishedDate) and (@PublishedDate) != false()"><xsl:value-of select="' '" /></xsl:when>
        <xsl:otherwise>
                <xsl:value-of select="ddwrt:GenDisplayName(string(@PublishedDate))" />

Change ddwrt:GenDisplayName(string(@PublishedDate)) to substring(@PublishedDate,1,7). Like following,


<xsl:when test="not (@PublishedDate) and (@PublishedDate) != false()"><xsl:value-of select="' '" /></xsl:when>
        <xsl:otherwise>
                <xsl:value-of select="substring(@PublishedDate,1,7)" />

And you should get this as result

James Tsai .Net SharePoint Blog - DFWP XSL After Change Heading Values

You can also change Group Heading to display in format YYYY-MMM (like the one in first screen shot) , or anything you like by changing above XSL.

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

James Tsai

Blog Disclaimer