Sunday, May 25, 2008

Which control causes the PostBack

In the page life cycle the Click event, SelectedIndexChanged event and other events raised by the UI controls are called after Page_Load event. But in many case we need to know which control causes the post back in Page_Load/Init function. If we are working with dynamic controls or other complex UI then this information we often need.
To determine if a control causes the Postback or not we can use the following function:

private Boolean CheckIfTheControlCausesPostBack(Control ctr)
{
   String ctrID = this.Page.Request.Params["__EVENTTARGET"];
   if (ctrID != null && ctrID != "")
   {
      String newctrID = ctrID.Replace("$", "_");
      if (newctrID == ctr.ClientID)
      return true;
   }
   else if (ctr.GetType().ToString() == "System.Web.UI.WebControls.ImageButton" || ctr.GetType().ToString() == "System.Web.UI.WebControls.Button")
   {
      String controlID = ctr.ClientID;
      String controlIDX = ctr.ClientID + ".x"; 
      String controlIDY = ctr.ClientID + ".y";
      foreach (String key in this.Page.Request.Form.AllKeys)
      {
         String newKey = key.Replace("$", "_");
         if (newKey == controlID || newKey == controlIDX || newKey == controlIDY)
         {
            return true;
         }
      }
    }
    return false; 
}

Understanding Code:
In most cases, this.Page.Request.Params["__EVENTTARGET"] contains the ID of control that causes Postback. But for Button and ImageButton the property remains empty string. Rather the control ID can be found in this.Page.Request.Form.AllKeys collection. So we have to loop through the collection and find if the ID exists. Notice I am concatenating “.x” and “.y” with control ID. This is because if the control is ImageButton then in that collection it contains ControlID + “.x” and ControlID + “.y” rather than ControlID.

And I am also replacing “$” sign with “_”, because if the control contains in other container (Panel, UserControl etc) then the ClientID of that control is ContainerID1_ContainerID2_ControlID; whereas in the collection it contains ContainerID1$ContainerID2$ControlID. So we have to replace that symbol before comparing.

To know more about Page Life Cycle: ASP.NET Page Life Cycle Overview

Sunday, May 18, 2008

Sharepoint Object Browser

Introduction
This application is a SharePoint site object browser which shows all the contents of a SharePoint site in a tree structure. The main objective of this sample program is to show; how to use SharePoint object model. This sample code is a very easy view of SharePoint development. But to develop in SharePoint these are must a developer should know.

Background
There are lots of sample and help about SharePoint administration and customization. But there are very few samples and examples in SharePoint programming. At the beginning, we really had to struggle to develop WebPart and to understand how object model and other SharePoint stuff work. I am working in SharePoint project for nearly one year and I felt to share some of my experiences with others using different sample application. And this is my first example.

What this application does?
This is a SharePoint site object browser application. In the textbox, followed by label Site Address, enter a SharePoint site address and then press Go button. You will see all subsites and content of subsites will be generated in a tree form in the TreeView control. In that control, if you click on a tree node of type list then the list’s contents will be shown in the bottom DataGridView. In the Grid you will find all columns and rows of that particular list. Even some columns, you will see here, will not be visible from SharePoint site. You can also select a column from the DropDownList and can update value for all rows for that particular column. But as I told, you will be able to see some SharePoint internal columns, those values we can not update.

Download Code
I have published the article on CodeProject. So you can download the source code from there. Link.

Understanding the code
We can take SharePoint site instance (SPSite) from site’s URL. Then we can access that SPSite object’s properties.
uxBrowser.Nodes.Clear();
SPSite site = new SPSite(uxAddress.Text);
TreeNode rootNode = uxBrowser.Nodes.Add(site.Url);
uxBrowser.NodeMouseClick += new TreeNodeMouseClickEventHandler(uxBrowser_NodeMouseClick);
for (Int32 i = 0; i < site.AllWebs.Count; i++)
  {
     SPWeb web = site.AllWebs[i];
     TreeNode webNode = rootNode.Nodes.Add(web.Name);
     for (Int32 j = 0; j < web.Lists.Count; j++)
     {
        SPList list = web.Lists[j];
        TreeNode listNode = webNode.Nodes.Add(list.Title);
        listNode.Tag = list;
     }
  } 
Here you can see, fist we are creating an instance of SPSite from a string (site URL) then we are getting AllWebs which is a collection of SPWeb objects. After that we loop through all SPWeb objects and it contents and extracting its information. While doing so, we are also adding these objects’s name and reference (saving in Tag property) in the TreeView control to generate the tree.
Now if you click on list type tree node, it will take the list reference from the Tag property.
_CurrentSelectedList = ((SPList)e.Node.Tag);
Then Fields property of_CurrentSelectedList will return the column collection of that list and finally _CurrentSelectedList.Items will return all rows (items) in that list. To make the data more presentable, I have added all contents in a DataTable then Bind it to the DataGridView.
When the user clicks on list type tree node, I am also assigning the DataTable as Data Source of the DropDownList. Now the user can select a column and update the column’s value. But one problem may arise, while updating the list; if the user does not have permission to update then it will generate an error. This can be solved by impersonating the Sharepoint\system user by using the SPSecurity.RunWithElevatedPrivileges method. This is a technique to use Object Model with full privilege.
SPSecurity.RunWithElevatedPrivileges(delegate()
  {
     using (SPSite ElevatedsiteColl = new SPSite(siteAddress))
     {
       ElevatedsiteColl.AllowUnsafeUpdates = true;
       using (SPWeb ElevatedSite = ElevatedsiteColl.OpenWeb(webName))
       {
          ....
       }
     }
  });

In between this method, the code will execute with an Administrative (Sharepoint\system) privilege. So we will be able to do any kind of read/update/delete operation. In the code you may also have noticed that I am initiating SPSite, SPWeb (those are created repeatedly) in a using block. This is because SPSite and SPWeb is very resource consuming object. So we have to make sure the instance gets disposed after its use.
Conclusion
I keep the source as simple as possible. Still if someone feels that some areas needed to explain more, you are welcome to ask me.