Passing any value to FileUpload.FileName using a button click - asp.net

Despite the firing of the method associated with a form and button click, my fileupload will not pass a value to a string, am I doing something obviously wrong (or just wrong in general)?
Do I need to attach a handler to the fileupload
Here is some sample source, note, it is the only code in the project, I have not made any definitions to the button or fileupload anywhere else:
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Protected Sub Button_Click()
Dim FileUpload1 As New FileUpload()
Dim X As String = FileUpload1.FileName
Response.Write(X)
End Sub
End Class
and the form:
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="Test.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button_Click" text="Submit"/>
<%-- <input type="file" />--%>
</form>
</body>
</html>
After trying FileUpload.HasFile, it appears as though not only can I not get the file name (described to me in the answer below), but the FileUpload.HasFile is nothing when a file is associated with it as well, is there any reason for this?
Protected Sub Button_Click()
Dim FileUpload1 As New FileUpload()
'Dim X As String = FileUpload1.FileName
'Response.Write(X)
If (FileUpload1.HasFile) Then
' Do Something
' SaveFile(FileUpload1.PostedFile)
Else
End If
End Sub

If you are looking for the path of the uploaded file in the client's machine, that is not allowed for security reasons.
However you should be able to get just the file name using the FileName property.
I check the file name in my applications when i want to test the to see the filetype that is uploaded.
I do not think the following line is required in your Protected Sub Button_Click() function:
Dim FileUpload1 As New FileUpload()
That must be creating a new instance causing it to show you an empty File Name.
If you just need the file name and not the entire path you could try the above.
Edit: Just saw the edit to your questions. The line I asked you to remove may be causing HasFile property to be empty as well.

You can not pass/assign name asp:FileUpload, as it is converted to input type file it is not allowed due to security reason. As it could breach the security of client machine that is browsing the website. The only possibility to assign it a value is through user selection that is browsing and assigning the file by user from client (browser)
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.fileupload.saveas.aspx
You can use FileUpload.SaveAs method to save the selected file.
FileUpload1.SaveAs(savePath);

Related

find control on page using vb.net

I'm using the FindControl function to look for a control on the page. It seems super simple and straight forward on MSDN but I can't get it to find the control. The page I'm using has a MasterPageFile that prepends more to the id that I give the contorl in the aspx file. A simple example that isn't working:
aspx page
<%# Page Title="Inventory Control Test" Language="VB" AutoEventWireup="false" MasterPageFile="~/Site.master" CodeFile="Default2.aspx.vb" Inherits="Sales_ajaxTest_Default2" %>
<asp:Content ID="conHead" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="conBody" ContentPlaceHolderID="MainBody" Runat="Server">
<asp:Button ID="saveAllBtn" runat="server" Text="Save All" />
</asp:Content>
code behind
Partial Class Sales_ajaxTest_Default2
Inherits System.Web.UI.Page
Protected Sub saveAllBtn_Click(sender As Object, e As System.EventArgs) Handles saveAllBtn.Click
Dim myControl1 As Control = FindControl("ctl00_MainBody_saveAllBtn")
If (Not myControl1 Is Nothing) Then
MsgBox("Control ID is : " & myControl1.ID)
Else
'Response.Write("Control not found.....")
MsgBox("Control not found.....")
End If
End Sub
End Class
I get that msgbox isn't a web thing I'm just using it for this example.
If i use "saveAllBtn", which is the id given to the control, in the FindControl I get "control not found". If I try this, on a stand alone page without a masterpage it works fine.
If I inspect the element using chrome I find that the ID of the button has been changed to "ctl00_MainBody_saveAllBtn" but if I use that in the FindControl I still get "control not found"
When you use FindControl you would specify the "server ID" (what you named it) of the control, not the final rendered "client ID" of the control. ex:
Dim myControl as Control = MainBody.FindControl("saveAllBtn")
However, in your specific example, since you are in the saveAllBtn.Click event, the control you are looking for is actually the sender parameter (because you clicked on that button to trigger the event you are in) ex:
Dim myControl as Button = CType(sender, Button)
If you just want to find saveAllBtn control, wweicker's second method using CType(sender, Button) is the prefer one.
However, if you want to find other control by name, you cannot use just FindControl. You need to find the control recursively, because it is nested inside other controls.
Here is the helper method -
Protected Sub saveAllBtn_Click(sender As Object, e As EventArgs)
Dim button = TryCast(FindControlRecursive(Me.Page, "saveAllBtn"), Button)
End Sub
Public Shared Function FindControlRecursive(root As Control, id As String) As Control
If root.ID = id Then
Return root
End If
Return root.Controls.Cast(Of Control)().[Select](Function(c) FindControlRecursive(c, id)).FirstOrDefault(Function(c) c IsNot Nothing)
End Function
Note: My VB code might be a bite weird, because I wrote in C# and converted to VB using converter.
FindControl does not work recursively. You must start at one point (Me, for example), and if that is not the control your looking for, search the Controls collection of your starting point. And so forth.

ASP.NET - Two User Controls - Multiple Instances Added at Runtime

I have a VB ASP.NET web application with two User Controls each containing one text input. There are two submit buttons each corresponding to one of the User Controls.
Clicking a button adds an instance of its corresponding User Control. For the most part this works except that in a specific scenario the IDs of the textboxes get mixed up thereby mixing up previously entered values.
The problem scenario is as follows:
1) Click the second button (the Add Approver button) twice and enter some values in the two resulting textboxes (for ease of analysis make the values different).
2) Click the first button (the Add Document button) once. (There is no need to add any value in the resulting textbox here.)
At this point everything appears correct. Viewing the page source, I see that the two "Approver" textboxes have IDs of ctl02_txtApprover and ctl03_txtApprover and the one "Document" textbox has an ID of ctl04_txtDocument.
Click the first button (the Add Document button) again.
At this point the value in the first "Approver" textbox disappears. The value in the second "Approver" textbox migrates to the first "Approver" textbox. Viewing the page source, the IDs for the two "Approver" textboxes have changed to ctl03_txtApprover and ctl04_txtApprover. The migrated values make sense considering that the textbox IDs have changed. In other words, the ViewState appears correct but the control IDs are incorrect.
I have made the code as simple as I can and have posted it here.
Default.aspx
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplicationUserControlTest._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:PlaceHolder ID="phDocument" runat="server" />
<asp:Button ID="btnAddDocument" runat="server" Text="Add Document" />
<br /><br />
<asp:PlaceHolder ID="phApprover" runat="server" />
<asp:Button ID="btnAddApprover" runat="server" Text="Add Approver" />
</form>
</body>
</html>
Default.aspx.vb
Public Class _Default
Inherits System.Web.UI.Page
Private Const VIEWSTATE_DOCUMENT_COUNT As String = "DocumentCount"
Private Const VIEWSTATE_APPROVER_COUNT As String = "ApproverCount"
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
ViewState(VIEWSTATE_DOCUMENT_COUNT) = 0
ViewState(VIEWSTATE_APPROVER_COUNT) = 0
Else
're-display any preexisting dynamic sections on postback
AddAllDocumentInfoSections()
AddAllApproverSections()
End If
End Sub
Protected Sub btnAddDocument_Click(sender As Object, e As EventArgs) Handles btnAddDocument.Click
ViewState(VIEWSTATE_DOCUMENT_COUNT) += 1
AddDocumentSection()
End Sub
Protected Sub btnAddApprover_Click(sender As Object, e As EventArgs) Handles btnAddApprover.Click
ViewState(VIEWSTATE_APPROVER_COUNT) += 1
AddApproverSection()
End Sub
Private Sub AddAllDocumentInfoSections()
For i As Integer = 0 To ViewState(VIEWSTATE_DOCUMENT_COUNT) - 1
AddDocumentSection()
Next
End Sub
Private Sub AddAllApproverSections()
For i As Integer = 0 To ViewState(VIEWSTATE_APPROVER_COUNT) - 1
AddApproverSection()
Next
End Sub
Private Sub AddDocumentSection()
Dim c As UserControl = LoadControl("~/Document.ascx")
phDocument.Controls.Add(c)
End Sub
Private Sub AddApproverSection()
Dim c As UserControl = LoadControl("~/Approver.ascx")
phApprover.Controls.Add(c)
End Sub
End Class
Document.ascx
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="Document.ascx.vb" Inherits="WebApplicationUserControlTest.Document" %><asp:TextBox ID="txtDocument" runat="server" /><br /><br />
Approver.ascx
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="Approver.ascx.vb" Inherits="WebApplicationUserControlTest.Approver" %><asp:TextBox ID="txtApprover" runat="server" /><br /><br />
I am using Visual Studio 2010. The Target Framework is 4.0. I have tried changing the clientIDMode but this does not seem to make a difference. Have I run into a bug with .NET or is there something wrong with my code?
There is something wrong with your code.
If you dynamically add controls to the same naming container in a control tree, then you need to add them in the same order after each postback.
In your case, you're not doing this.
At your step 2, you have added three controls in this order:
Approver 1 (AddAllApproverSections)
Approver 2 (AddAllApproverSections)
DocumentInfo 1 (btnAddDocument_Click)
But then after the postback, you regenerate them in the following order:
DocumentInfo 1 (AddAllDocumentInfoSections)
Approver 1 (AddAllApproverSections)
Approver 2 (AddAllApproverSections)
Hence the control ids aren't the same, and the problems you're seeing.
One solution might be to store additional information in ViewState that represents the order the controls were added, so that you can recreate them in the same order.
But I'd probably be inclined to go for a different approach, for example put the DocumentInfo sections into the template of a Repeater, and the Approver sections into a second Repeater. Each Repeater would be data bound to a suitable collection, and adding an item (Approver or DocumentInfo) would be achieved by adding an element to the relevant collection and calling DataBind.
The problem here is that you are modifying the Controls collection and ViewState after they have been initialized. You should never dynamically add controls in the Page Load event.
You need to add your controls in the Page_Init stage of the Page life cycle, and remove the code from the else statement in your Page_Load event. Your new Page_Init event would look like this:
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
AddAllDocumentInfoSections()
AddAllApproverSections()
End Sub
I believe you may have to change the way you're storing the "count" for these controls, as the View State information is not yet available at this stage. I would just store it as a Session variable, in that case. You'd just need to change your reference to "ViewState" throughout that code sample with "Session", like this:
Private Sub AddAllDocumentInfoSections()
For i As Integer = 0 To Session(VIEWSTATE_DOCUMENT_COUNT) - 1
AddDocumentSection()
Next
End Sub

iTextSharp .pdf tool

Afternoon All,
I have been advised that i can use iTextSharp to help me convert my web pages into .PDF files. I am using the following link as a sample tutorial but cannot generate the .pdf?
Visit http://www.dotnetspark.com/kb/654-simple-way-to-create-pdf-document-using.aspx
I am using the VB sample. I have added the iTextSharp.dll to my project and added the namespaces as requested. I have simply created a blank page and added a button to the page and using the following code i cant seem to get this to generate the file?
Here is my code...
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Partial Class pdf
Inherits System.Web.UI.Page
Protected Sub btnGeneratePDF_Click(ByVal sender As Object, ByVal e As EventArgs)
'Create Document class obejct and set its size to letter and give space left, right, Top, Bottom Margin
Dim doc As New Document(iTextSharp.text.PageSize.LETTER, 10, 10, 42, 35)
Try
Dim wri As PdfWriter = PdfWriter.GetInstance(doc, New FileStream("d:\myfolder\test.pdf", FileMode.Create))
'Open Document to write
doc.Open()
'Write some content
Dim paragraph As New Paragraph("This is my first line using Paragraph.")
Dim pharse As New Phrase("This is my second line using Pharse.")
Dim chunk As New Chunk(" This is my third line using Chunk.")
' Now add the above created text using different class object to our pdf document
doc.Add(paragraph)
doc.Add(pharse)
doc.Add(chunk)
Catch dex As DocumentException
'Handle document exception
Catch ioex As IOException
'Handle IO exception
Catch ex As Exception
'Handle Other Exception
Finally
'Close document
doc.Close()
End Try
End Sub
End Class
Here is the code for the button...
<%# Page Language="VB" AutoEventWireup="false" CodeFile="pdf.aspx.vb" Inherits="pdf" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnGeneratePDF" runat="server" Text="Generate .PDF" />
</div>
</form>
</body>
</html>
Could someone please take a look at this for me and let me know where i am going wrong?
Regards
Betty
Not sure if this will fix it all, but you're at least missing the Click_Event from your buttton.
<asp:Button ID="btnGeneratePDF" runat="server" Text="Generate .PDF" OnClick="btnGeneratePDF_Click" />
(And I see that you asked this question yesterday: Button ClickEvent is not triggered with the same problem, try to remember next time ;-))

asp.net FindControl Recursively

This is a really weird one - I will do my best to explain.
I have a basic master page:
<%# Master Language="VB" CodeFile="MasterPage.master.vb" Inherits="master_MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
<asp:PlaceHolder ID="PH1" runat="server" />
<asp:PlaceHolder ID="PH2" runat="server" />
</div>
</form>
</body>
</html>
And a standard child page:
<%# Page Title="" Language="VB" MasterPageFile="~/master/MasterPage.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="master_Default" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>
I have the following extension methods for finding controls recursively:
Option Strict On
Option Explicit On
Imports System.Runtime.CompilerServices
Imports System.Web.UI
Public Module ExtensionMethods
<Extension()> _
Public Function FindControlRecursively(ByVal parentControl As System.Web.UI.Control, ByVal controlID As String) As System.Web.UI.Control
If parentControl.ID = controlID Then
Return parentControl
End If
For Each c As System.Web.UI.Control In parentControl.Controls
Dim child As System.Web.UI.Control = FindControlRecursively(c, controlID)
If child IsNot Nothing Then
Return child
End If
Next
Return Nothing
End Function
<Extension()> _
Public Function FindControlIterative(ByVal rootControl As Control, ByVal controlId As String) As Control
Dim rc As Control = rootControl
Dim ll As LinkedList(Of Control) = New LinkedList(Of Control)
Do While (rc IsNot Nothing)
If rc.ID = controlId Then
Return rc
End If
For Each child As Control In rc.Controls
If child.ID = controlId Then
Return child
End If
If child.HasControls() Then
ll.AddLast(child)
End If
Next
rc = ll.First.Value
ll.Remove(rc)
Loop
Return Nothing
End Function
End Module
I have a control with a listview:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="control-1.ascx.vb" Inherits="controls_control_1" %>
<p>
Control 1</p>
<asp:ListView ID="lv" runat="server">
<ItemTemplate>
<div>
<asp:Literal ID="Name" runat="server" Text='<%#Eval("Name") %>' />
<asp:LinkButton ID="TestButton" runat="server">Test</asp:LinkButton>
</div>
</ItemTemplate>
</asp:ListView>
That is databound:
Partial Class controls_control_1
Inherits System.Web.UI.UserControl
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Dim l As New List(Of Person)
Dim j As New Person
j.Name = "John"
l.Add(j)
lv.DataSource = l
lv.DataBind()
End If
End Sub
End Class
Public Class Person
Public Property Name As String
End Class
I have a second control that is very basic:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="control-2.ascx.vb" Inherits="controls_control_2" %>
<p>Control 2</p>
In my child page, I have the following code to load the controls:
Option Strict On
Option Explicit On
Partial Class master_Default
Inherits System.Web.UI.Page
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
Dim controlInstance1 As System.Web.UI.Control = LoadControl("~/controls/control-1.ascx")
controlInstance1.ID = "control_1"
Dim zone As System.Web.UI.Control = Me.Master.FindControlRecursively("PH1")
zone.Controls.Add(controlInstance1)
Dim controlInstance2 As System.Web.UI.Control = LoadControl("~/controls/control-2.ascx")
controlInstance2.ID = "control_2"
Dim zone2 As System.Web.UI.Control = Me.Master.FindControlRecursively("PH2")
zone2.Controls.Add(controlInstance2)
End Sub
End Class
This loads the controls, but if I click the Test button in the listview, the page loses the data in the listview after postback.
If I change the FindControlRecursively calls to FindControlIterative, when I click the test button, the data in the listview is retained after the postback.
Anybody have any idea what the FindControlRecursively call might be doing to cause the listview to lose it's data? This only happens if control-2 is added to the page - if it is not, and control-1 is loaded using FindControlRecursively, data is retained correctly after postback.
Thanks in advance...this one is driving me nuts, and it took me a while to figure out where exactly it was breaking down.
Why don't you simply expose properties that return PH1 and PH2, because the master has the reference of them and you don't need to iterate all child controls of master:
Public ReadOnly Property Container1 As PlaceHolder
Get
Return Me.PH1
End Get
End Property
Public ReadOnly Property Container2 As PlaceHolder
Get
Return Me.PH2
End Get
End Property
You can access them:
Dim ph1 As PlaceHolder = DirectCast(Me.Master, myMaster).Container1
Dim ph2 As PlaceHolder = DirectCast(Me.Master, myMaster).Container2
Another problem is this line:
controlInstance1.ID = "control_2"
You are setting only controlInstance1's ID twice, but that doesn't cause your issue.
Your main problem is that you are adding the controls to the placeholders in Page_Init instead of Page_Load. Therefore the UserControls can't load their ViewState and the ListView is empty. Recreate them in Page_Load and it will work.
Edit: But i must admit that i don't know why your iterate extension wins over the recursive. The reference on the placeholders are the same, they shouldn't work both, weird.
summary:
it works with my properties,
putting all in page's load event handler instead init
with your iterate-extension(for whatever reasons)
It also works if you add both UserControls at last, after you've found the placeholders via FindControlRecursively.
zone.Controls.Add(controlInstance1)
zone2.Controls.Add(controlInstance2)
I'm losing motivation on this, but i'm sure you'll find the answer here. Controls.Add loads it's parent's ViewState into all childs and therefore it depends on when you add the controls, also the index of the controls in their parent controls must be the same on postback to reload the ViewState.
Your recursive extension method touches control1's ID after you've added it to PH1(while searching PH2), the iterative extension does not. I assume that this corrupts it's ViewState in Page_Init.
Conclusion Use properties instead
I figured out why I was seeing the behavior I described above. I changed the recursive function to the following:
<Extension()> _
Public Function FindControlRecursively(ByVal parentControl As System.Web.UI.Control, ByVal controlId As String) As System.Web.UI.Control
If String.IsNullOrEmpty(controlId) = True OrElse controlId = String.Empty Then
Return Nothing
End If
If parentControl.ID = controlId Then
Return parentControl
End If
If parentControl.HasControls Then
For Each c As System.Web.UI.Control In parentControl.Controls
Dim child As System.Web.UI.Control = FindControlRecursively(c, controlId)
If child IsNot Nothing Then
Return child
End If
Next
End If
Return Nothing
End Function
By adding the parentControl.HasControls check, I am preventing the function from searching the listview for child controls, and this allows the listview to load its viewstate later on in the page/control lifecycle.
Also, I tweaked my iterative function to make it more efficient and prevent it from bugging out if a control was not returned:
<Extension()> _
Public Function FindControlIteratively(ByVal parentControl As Web.UI.Control, ByVal controlId As String) As Web.UI.Control
Dim ll As New LinkedList(Of Web.UI.Control)
While parentControl IsNot Nothing
If parentControl.ID = controlId Then
Return parentControl
End If
For Each child As Web.UI.Control In parentControl.Controls
If child.ID = controlId Then
Return child
End If
If child.HasControls() Then
ll.AddLast(child)
End If
Next
If (ll.Count > 0) Then
parentControl = ll.First.Value
ll.Remove(parentControl)
Else
parentControl = Nothing
End If
End While
Return Nothing
End Function
Also, to follow up on my earlier description of the problem - I was able to reproduce the recursive function's intially weird behavior using the iterative function if I removed the If child.HasControls() Then check from the iterative function. Hope that makes sense.
In the end I am sticking with the iterative function because looping should be less expensive than recursion, though in real world scenarios the difference probably will not be noticeable.
The following links were extremely helpful to me in working this out:
http://msdn.microsoft.com/en-us/library/ms972976.aspx#viewstate_topic4
https://web.archive.org/web/20210330142645/http://www.4guysfromrolla.com/articles/092904-1.aspx
http://scottonwriting.net/sowblog/archive/2004/10/06/162995.aspx
http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx
Extra thanks to Tim for pointing me in the right direction.

Directory Structure within TreeView VB

Started to look at the Treeview control.
Is there anyway to tie the Tree View control into a Directory structure on the Web Server using Visual basic?
I have a lot of legacy files, which are updated and added often. Obviously I could code the structure in XML but this would be laborious and hard to train out to the end user.
I guess it would be a dynamic creation of an XML file perhaps?
Here's an elementary sample that I created awhile ago when learning to play with the TreeView. I have now converted the code to VB.NET using an online converter for your benefit.
It recursively walks the directory tree starting from the root of the virtual directory and creates nodes for each sub-directory or file encountered. I think this is exactly what you needed.
For visual separation, I had used icons to differentiate files from folders (folder.gif and file.gif). You can remove that parameter if you want.
Complete ASPX follows (You can paste it into a new page and it should run):
<%# Page Language="VB" %>
<%# Import Namespace="System.IO" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If Not Page.IsPostBack Then
Dim rootDir As New DirectoryInfo(Server.MapPath("~/"))
' Enter the RecurseNodes function to recursively walk the directory tree.
Dim RootNode As TreeNode = RecurseNodes(rootDir)
' Add this Node hierarchy to the TreeNode control.
Treeview1.Nodes.Add(RootNode)
End If
End Sub
Private Function RecurseNodes(ByVal thisDir As DirectoryInfo) As TreeNode
Dim thisDirNode As New TreeNode(thisDir.Name, Nothing, "Images/folder.gif")
' Get all the subdirectories in this Directory.
Dim subDirs As DirectoryInfo() = thisDir.GetDirectories()
For Each subDir As DirectoryInfo In subDirs
thisDirNode.ChildNodes.Add(RecurseNodes(subDir))
Next
' Now get the files in this Directory.
Dim files As FileInfo() = thisDir.GetFiles()
For Each file As FileInfo In files
Dim thisFileNode As New TreeNode(file.Name, Nothing, "Images/file.gif")
thisDirNode.ChildNodes.Add(thisFileNode)
Next
Return thisDirNode
End Function
</script>
<html>
<head>
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:treeview ID="Treeview1" runat="server"></asp:treeview>
</form>
</body>
</html>
A custom sitemap provider is a good bet.
There is a good article on 4guys title "Examining ASP.NET 2.0's Site Navigation - Part 4 "

Resources