|
Multiple File Upload...
The HtmlInputFile and the FileUpload controls allow the user to upload files to the server.
It would be nice to have a control that allows the user to upload more than one file at a time...
By: Brian Mains
Date: February 25, 2006
Download the code.
Printer Friendly Version
The HtmlInputFile and the FileUpload controls allow the user to upload files to the server.
FileUpload is a 2.0 addition server control that has most of the same features of the HtmlInputFile
control, but with a few added properties. However, it would be easier to have a control that allows
the user to upload more than one file at a time, or to allow the user to add a specific number of
input file boxes dynamically in the form.
Before we begin, you should be aware of some limitations. These controls do not store their
viewstate; they implement the methods of IPostBackDataHandler; however, the LoadPostData method
always returns false. Even overriding these methods yields no effect, as the value property for
the file upload is read-only. I’ve done some research, and supposedly in newer browsers this could
be set, but I have not come across a solution to do so.
If you read my article on the Collapsible Panel, you will have seen this event notation, where each
event has an ING and an ED event, one firing before the action takes place (while also allowing you
to cancel it), and one that fires afterward. This is the structure for events to add and clear
input boxes in the control. The control also implements IRepeatInfoUser, to render the file upload
boxes in a horizontal or vertical fashion, or creating a table structure. This just adds to the
versatility of the control, even though in most situations, it won’t be desired.
In the rendering process, I render Add and Clear links using the header or footer sections of the
render item. To determine this, the HasHeader and HasFooter methods of IRepeatInfoUser check the
LinkLocation property enumeration.
<Browsable(False)> _
Public ReadOnly Property HasFooter() As Boolean Implements System.Web.UI.WebControls.IRepeatInfoUser.HasFooter
Get
Return (Me.LinkLocation = LinkLocationType.Bottom)
End Get
End Property
<Browsable(False)> _
Public ReadOnly Property HasHeader() As Boolean Implements System.Web.UI.WebControls.IRepeatInfoUser.HasHeader
Get
Return (Me.LinkLocation = LinkLocationType.Top)
End Get
End Property
Public Sub RenderItem(ByVal itemType As System.Web.UI.WebControls.ListItemType, ByVal repeatIndex As Integer, ByVal repeatInfo As System.Web.UI.WebControls.RepeatInfo, ByVal writer As System.Web.UI.HtmlTextWriter) Implements System.Web.UI.WebControls.IRepeatInfoUser.RenderItem
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
If (itemType = ListItemType.Header OrElse itemType = ListItemType.Footer) Then
writer.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:" & Page.ClientScript.GetPostBackEventReference(Me, "add"))
writer.RenderBeginTag(HtmlTextWriterTag.A)
writer.Write(Me.AddLinkText)
writer.RenderEndTag()
writer.Write(" ")
writer.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:" & Page.ClientScript.GetPostBackEventReference(Me, "clear"))
writer.RenderBeginTag(HtmlTextWriterTag.A)
writer.Write(Me.ClearLinkText)
writer.RenderEndTag()
ElseIf (itemType = ListItemType.Item OrElse itemType = ListItemType.AlternatingItem) Then
Me.Controls(repeatIndex).RenderControl(writer)
End If
writer.RenderEndTag() '/td
writer.RenderEndTag() '/tr
End Sub
|
The fileupload controls are created in CreateChildControls and rendered above as the item. The
file boxes are based upon the InputBoxes property, which is an integer value, stating how many
input boxes to use for the control. This value is added or reset through the AddNew and Clear
methods, which AddNew adds one to it everytime, and Clear resets it back to one.
Protected Overrides Sub CreateChildControls()
For intI As Integer = 1 To Me.InputBoxes
Dim objBox As New FileUpload
objBox.ID = "fu" & intI
Me.Controls.Add(objBox)
Next
End Sub
|
This control also makes use of the method GetPostBackEventReference in the RenderItem method.
This method returns a javascript string with the function that will perform the posting back (which
is rendered in a link’s href property). The references are shown below; we use two event arguments
for this control: add and clear. RaisePostBackEvent handles the postback. It receives the event
argument, and calls the appropriate method.
'In RenderItem method, rendered in the HREF property of an <a>
Page.ClientScript.GetPostBackEventReference(Me, "add")
Page.ClientScript.GetPostBackEventReference(Me, "clear")
Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
Dim strArg As String = eventArgument.ToLower()
If (strArg = "add" OrElse strArg = "addnew") Then
AddNew()
ElseIf (strArg = "clear") Then
Clear()
End If
End Sub
|
This control also makes use of IPostBackDataHandler and uses the LoadPostData method to check any
possible uploaded files, and if there is one, raise an event. This allows the developer to handle
the uploading of the file. As an alternative, this control could handle that action through an
automated means by using an UploadFolder property, referencing a folder on the web server.
Public Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As System.Collections.Specialized.NameValueCollection) As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
Me.EnsureChildControls()
For Each objControl As Control In Me.Controls
If (TypeOf (objControl) Is FileUpload) Then
Dim objUpload As FileUpload = CType(objControl, FileUpload)
If (objUpload.HasFile) Then
OnInputBoxPosted(New PostedFileEventArgs(objUpload.PostedFile))
End If
End If
Next
End Function
|
For the control to receive postbacks, you have to call Page.RegisterRequiresPostBack method. This
will then allow LoadPostData to fire.
Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
MyBase.OnPreRender(e)
If (Page IsNot Nothing) Then
Page.RegisterRequiresPostBack(Me)
End If
End Sub
|
This control works well with allowing users to upload multiple files. If using the links (add and
clear), you may want to list a disclaimer stating that the user should add the desired number of
textboxes first before browsing to all of the files, as they won’t be saved. Also, the control
allows you to upload the files through a button of your own. If you don’t want the add/clear links
shown, set the LinkLocation property to the None enumeration, and they will disappear.
This class comes with a PostedFileEventArgs that contains details about the posted file, which is
made available to the user in the InputBoxPosted event. It is defined below.
Public Class PostedFileEventArgs
Inherits System.EventArgs
Private m_objFile As HttpPostedFile
Public ReadOnly Property FileName() As String
Get
Return m_objFile.FileName
End Get
End Property
Public ReadOnly Property FileStream() As Stream
Get
Return m_objFile.InputStream
End Get
End Property
Public Sub New(ByVal objFile As HttpPostedFile)
m_objFile = objFile
End Sub
Public Sub SaveAs(ByVal strFilePath As String)
m_objFile.SaveAs(strFilePath)
End Sub
End Class
|
When the test page runs, test the links for adding/clearing. Also, try setting the InputBoxes
property, and play around with the IRepeatInfoUser properties to change the layout. Lastly, when
you upload files, it will render the name of the file in the page.
|