AJAX Style Folder Browser, Part II

In a previous post I discussed how to use combine the TreeView, GridView and UpdatePanel controls to create an AJAX style folder browser.  I tagged this previous post as 'prototype' with the intentions of coming back to it and updating it to something that is more production ready.  This evening I found some time to work on it again.  I made a couple of enhancements that help both the usability (no more full postback when a folder is clicked in the right hand pane) as well as the codebehind (I created a FileSystemDataSource control for interacting with the file system)  

Live Demo: AJAX Folder Browser

Download: Sample Web Site

[Update 7/25/07] Thanks to some feedback from Bilal, I fixed a bug where clicking on the pdf text would cause the famous PageRequestManagerParserError.  The problem was that I registered the ImageButton as a postback control, but not the LinkButton.  This has now been fixed and the sample site and live demo has been updated.  Thanks Bilal.

FileSystemDataSource

I am now binding the left pane (the one that shows the folders) to a custom FileSystemDataSource hierarchical datasource control.  I found a (broken!) example on msdn which got me started, but I had to do some extra research before I was able to get it working properly (I will write another post about this real soon).  Besides fixing this bug, I also enhanced the FileSystemDataSource to support 2 extra features: optionally returning only folders, and providing a root path (the original control assumed the root folder was the root of the application).  Here is what the markup for this control and treeview looks like.  'public_dir' is the folder in the root directory that I want the users to be able to browse.

<mb:FileSystemDataSource ID="fileSystemDataSource" runat="server" RootPath="public_dir" FoldersOnly="true" />
<asp:TreeView ID="tvFolders" runat="server" DataSourceID="fileSystemDataSource"
    OnSelectedNodeChanged="TvFolders_SelectedNodeChanged">
    <NodeStyle ImageUrl="Img/folder.gif" HorizontalPadding="3px" />
    <SelectedNodeStyle Font-Underline="true" />
</asp:TreeView> 

There are a number of classes that need to be implemented when creating a custom hierarchical datasource.  You can download the sample and browse through it if you like. 

RegisterPostBackControl

In the original example, any postback that originated in the GridView would cause the complete page to postback.  I did this because if the user clicked on a .pdf file, I need to write the contents to the Response object.  If this was done in a async postback, it would cause an exception back on the client - you can't write to the Response object directly during an async postback.  So now when the folder icon is clicked an async postback executes, but when the .pdf icon is clicked a full postback executes and the .pdf file is sent back to the client via the Response.  To make this possible, I removed the explicit full postback trigger from the updatepanel and instead register the pdf ImageButton's as postback triggers programmatically using the ScriptManager object.  I am doing this in the RowDataBound event of the GridView.

protected void GvFolderItems_RowDataBound(object sender, GridViewRowEventArgs args)
{
    if (args.Row.RowType == DataControlRowType.DataRow)
    {
        ImageButton imageButton = (ImageButton)args.Row.FindControl("btnItemIcon");
        LinkButton linkButton = (LinkButton)args.Row.FindControl("btnItemName");

        if (args.Row.DataItem is System.IO.DirectoryInfo)
        {
            imageButton.ImageUrl = @"Img/folder.gif";
            imageButton.CommandName = "OpenFolder";
            linkButton.CommandName = "OpenFolder";
        }
        else
        {
            imageButton.ImageUrl = @"Img/pdf.gif";
            imageButton.CommandName = "OpenFile";
            linkButton.CommandName = "OpenFile";                

            // register both the linkbutton and imagebutton as full postback
            // controls
            ScriptManager scriptManager = ScriptManager.GetCurrent(this);
            scriptManager.RegisterPostBackControl(linkButton);
            scriptManager.RegisterPostBackControl(imageButton);

            System.IO.FileInfo fileInfo = (System.IO.FileInfo)args.Row.DataItem;
            Label lblSize = (Label)args.Row.FindControl("lblSize");
            lblSize.Text = string.Format("{0:N0} KB", fileInfo.Length / 1000);
        }
    }
}

TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/48

Comments


Hello Matthew,
If you click on pdf file itself, it is giving an AJAX Postback, maybe disabling the click or making the pdf and the icon both have the same event would solve the problem!

Thanks

Thanks Bilal - good catch. I should have made them have the same event. I will update the code snippet and sample tonight.

Posted by: barbod on August 4, 2007 12:00 AM

hi Matthew,
how can i select first node of Treeview when page load...
cause u use FileDataSource that TreeView (by default) cant show first node.
Thanks

Posted by: george on August 5, 2007 12:00 AM

any chance of allowing us to set any folder on the computer as the starting folder, instead of one thats in the root of the site?

Posted by: drew on August 22, 2007 12:00 AM

Can there be a flag so only the "root" folders are shown at first, instead of all folders? Is there something we can do to show "waiting" while a folder is selected and you wait to see the PDF files under it?

Posted by: Steve on September 13, 2007 12:00 AM

Matt, This is excellent!

Posted by: Daniel on October 2, 2007 12:00 AM

Matthew, I get the following: "element scriptmanager is not a known element" (amongst others) when I open your project. What am I missing ?
Thanks

Daniel -

Do you have ASP.NET AJAX installed? If not you can get it here

Matt.

Great Work! Ive made a few simple changes to change the root path to a unc path.

Is there any chance that you could post an example of how to add your own attributes into the gridview? such as LastAccessed?

Perhaps you could add more columns with general functions such as "delete" or "rename."

Posted by: jim on October 20, 2007 12:00 AM

Here is another way of doing it, more like a multi-column treeview with sorting:

http://www.digitaltools.com/GVT.aspx

Posted by: miki on December 10, 2007 12:00 AM

Its work. Thanks!!!!!

Posted by: Rashid on January 27, 2008 12:00 AM

Thankx Matt;
At last I found this web, I was searching and serching and never found anything that helped so much, I extramly like the way you are evolving this "Explorer"
I will try to post if I made any improvements

Posted by: Rashid on January 29, 2008 12:00 AM

Hi Matt;
I was viewing you example here. I was just wanting to ask you that.
we set the folder in the properties like (rootpath="public_dir"),
now lets suppose that there are two folders (A and B) inside the "public_dir" folder and we want to provide a textbox on the main page to get the root folder as "A" or "B" , then how to implement that.
please reply soon.

Posted by: Richard on February 25, 2008 12:00 AM

Matt,
Is there a way to change the root path? I wanted to access another folder on another server is there a way to make that happen?

Thanks,

Posted by: vitesh on April 8, 2008 12:00 AM

nice tutorial

Posted by: Justin on June 12, 2008 12:00 AM

That is a beautiful control and demo. I plugged it in and got got it up and going in a matter of minutes. EXCELLENT WORK!

Posted by: Tom on July 8, 2008 12:00 AM

Matt, thanx for a superb tip on registering postback without ASYNC. I was trapped by that ugly error and spent too much time searching for help. Your 1 line piece of code, in red font above, fixed me up perfect !!! Thanx, Tom

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • Tom wrote: Matt, thanx for a superb tip on registering postback without ASYNC. I was trapped by that ugly error...
  • Justin wrote: That is a beautiful control and demo. I plugged it in and got got it up and going in a matter of mi...
  • vitesh wrote: nice tutorial ...
  • Richard wrote: Matt, Is there a way to change the root path? I wanted to access another folder on another server i...
  • Rashid wrote: Hi Matt; I was viewing you example here. I was just wanting to ask you that. we set the folder in th...
  • Rashid wrote: Thankx Matt; At last I found this web, I was searching and serching and never found anything that he...
  • miki wrote: Its work. Thanks!!!!! ...
  • jim wrote: Here is another way of doing it, more like a multi-column treeview with sorting: <a href="http://ww...