Building a Vista Style Folder Browser with ASP.NET 3.5 and a Custom Hierarchical DataSource Control
A while back, I wrote a post describing how to create a folder browser with ASP.NET 2.0 using the TreeView, UpdatePanel, GridView (customized to always display header row) and a modified version of the FileSystemDataSource as described on MSDN. I have used this widget on a few different projects and I generally like how it works (you can view the demo here).
One thing my original implementation is clearly lacking is a professional look and feel. So I recently had the opportunity to upgrade it to .Net 3.5 and in the process I decided it was time to overhaul the style. Using the Vista folder explorer as my template, I made the following changes to the original sample ...
- Replaced the plus/minus icons with dark and light arrows
- Added soft blue rounded corners to the explorers container
- Added modified date column to the right hand pane
- Added a footer the displays the name and modified date of the currently selected folder
I have hit most of the implementation high points below - so read on if you are interested.
The MSDN documentation for the HierarchicalDataSourceControl provides a sample implementation for binding to files and folders. I took this sample implementation and made a handful of minor modifications, including specifying if you would like folders and files retrieved or just folders. Here is a sample configuration that is used for the above screen shot.
If you do not want the root folder to be displayed, just set the IncludeRoot attribute to false and the folders will render as follows (notice there is no top level root node anymore). In my original post I received quite a few questions about how this could be done so I figured I would add it in with this example.
Configuring the Folder TreeView
After setting up the datasource, I went ahead and created the markup for the TreeView that displays that folders. Most of the markup is for controlling the styling. I have added CssClasses for the tree's container as well as custom classes for nodes and selected nodes. I have also added an event handler for the SelectedNodeChanged event so I can update the right hand pane with the selected folders contents as the user selects different folders from the left hand pane.
Folder Contents ListView
I am using ASP.NET 3.5's new ListView control to handle rendering the right hand pane of the folder browser. This is just a standard HTML table with 3 columns: Name, Date modified and Size. I also added an EmptyDataTemplate that renders the 'This folder is empty' where there are no items in the selected folder. When the user selects a folder from the left hand pane, I programmatically fetch all of the FileSystemInfo objects for the selected folder and assign this collection to the ListView's DataSource property.
I am also attaching to the ListView's ItemDataBound and ItemCommand event handlers. From the ItemDataBound handler, I need to check if the FileSystemInfo object being bound to is a FileInfo or DirectoryInfo object. If it is a DirectoryInfo, I need to assign the folder icon. If it is a file I need to calculate the size of the file as well as set the pdf file icon. For the case where the databound item is a FileInfo object I am also registering the image and link buttons as full postback controls so the file can be properly written to the Response stream when the user clicks on either of the buttons. Failing to do this will cause that dreaded PageRequestManagerParserErrorException - the UpdatePanel doesn't like the Response object to be modified directly.
Note: If you have a terrible memory like me, make sure you bookmark the ListViewDataItem class. It shows an example of how to access the databound item from the ItemDataBound event handler. If the ItemType of the ListViewItem is a DataItem, you can cast the ListViewItem as a ListViewDataItem and use the DataItem property to get at the databound item (FileSystemInfo's for my example). From using the GridView, I got used to getting right at the data item from the DataBound event handler - with the ListView you have to do just a little bit more work.
Folder Detail Footer
If you look back at the demo page or screen shot below, you will also notice that I included some additional context information for the selected folder in the browsers footer. This is just a DetailsView that I bind as the user changes the selected folder.
The IE6 Doubled Float-Margin Bug
I chose to use a floating DIV for the left pane portion of the control. In doing so I bumped into an IE6 bug that I am sure most of you are familiar with - in certain situations IE6 doubles the margins of containers that are floated. Here is a good description of the problem and a solution. Another browser specific quirk to try to remember when troubleshooting ...
I like my new Vista styled explorer - much better looking than the original incarnation. But I didn't get to everything I wanted. Here are a few of the remaining items that I still need to add ...
- Add sorting to the column headers
- Add a progress indicator while the folder listings are being retrieved
- Add support for scrolling the right hand pane. Ideally, freeze the column headers and save a little room to the right of the pane for the scroll bar.
That's it. Enjoy!