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...
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.