Pues si algunos estamos sufriendo esta insoportable lentitud pero a otros como Songoku le va rápido la navegación pues... entonces ¿Que está pasando aquí? xD
Saludos!
Saludos!
Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.
Mostrar Mensajes MenúCita de: makorro en 21 Octubre 2013, 16:38 PMquiero hacer que todos los eventos keypress los maneje el form
Cita de: makorro en 21 Octubre 2013, 16:38 PMLeí que tengo que poner en true la propiedad KeyPressEventArgs.Handled
' /* *\
' |#* ListView Elektro *#|
' \* */
'
' // By Elektro H@cker
'
' Properties:
' ...........
' · Disable_Flickering
' · Double_Buffer
' · GridLineColor
' · ItemHighlightColor
' · ItemNotFocusedHighlighColor
' · DrawCustomGridLines
' · UseDefaultGridLines
' · Enable_ProgressBar
' · Progressbar_Column
' · Percent
' · Percent_Decimal
' · Percent_Font
' · Percent_Text
' · Percent_Forecolor
' · Percent_Text_Allignment
' · ProgressBar_BackColor
' · ProgressBar_BorderColor
' · ProgressBar_FillColor1
' · ProgressBar_FillColor2
'
' Events:
' .......
' · ItemAdded
' · ItemRemoved
'
' Methods:
' .......
' · AddItem
' · RemoveItem
Public Class ListView_Elektro : Inherits ListView
Public Event ItemAdded()
Public Event ItemRemoved()
Private _Disable_Flickering As Boolean = True
Private _gridLines As Boolean = False
Private _useDefaultGridLines As Boolean = False
Private _gridLineColor As Color = Color.Black
Private _itemHighlightColor As Color = Color.FromKnownColor(KnownColor.Highlight)
Private _itemNotFocusedHighlighColor As Color = Color.FromKnownColor(KnownColor.MenuBar)
Private _enable_progressbar As Boolean = False
Private _progressbar_column As Integer = Nothing
Private _percent As Double = 0
Private _percent_decimal As Short = 2
Private _percent_text As String = "%"
Private _percent_text_allignment As StringAlignment = StringAlignment.Center
Private _percent_stringformat As StringFormat = New StringFormat With {.Alignment = _percent_text_allignment}
Private _percent_font As Font = Me.Font
Private _percent_forecolor As SolidBrush = New SolidBrush(Color.Black)
Private _progressBar_backcolor As SolidBrush = New SolidBrush(Color.Red)
Private _progressBar_bordercolor As Pen = New Pen(Color.LightGray)
Private _progressBar_fillcolor1 As Color = Color.YellowGreen
Private _progressBar_fillcolor2 As Color = Color.White
Public Sub New()
Me.Name = "ListView_Elektro"
Me.DoubleBuffered = True
Me.UseDefaultGridLines = True
' Set Listview OwnerDraw to True, so we can draw the progressbar inside.
If Me.Enable_ProgressBar Then Me.OwnerDraw = True
' Me.GridLines = True
' Me.MultiSelect = True
' Me.FullRowSelect = True
' Me.View = View.Details
End Sub
#Region " Properties "
''' <summary>
''' Enable/Disable any flickering effect on the ListView.
''' </summary>
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
If _Disable_Flickering Then
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or &H2000000
Return cp
Else
Return MyBase.CreateParams
End If
End Get
End Property
''' <summary>
''' Set the Double Buffer.
''' </summary>
Public Property Double_Buffer() As Boolean
Get
Return Me.DoubleBuffered
End Get
Set(ByVal Value As Boolean)
Me.DoubleBuffered = Value
End Set
End Property
''' <summary>
''' Enable/Disable the flickering effects on this ListView.
'''
''' This property turns off any Flicker effect on the ListView
''' ...but also reduces the performance (speed) of the ListView about 30% slower.
''' This don't affect to the performance of the application itself, only to the performance of this control.
''' </summary>
Public Property Disable_Flickering() As Boolean
Get
Return _Disable_Flickering
End Get
Set(ByVal Value As Boolean)
Me._Disable_Flickering = Value
End Set
End Property
''' <summary>
''' Changes the gridline color.
''' </summary>
Public Property GridLineColor() As Color
Get
Return _gridLineColor
End Get
Set(ByVal value As Color)
If value <> _gridLineColor Then
_gridLineColor = value
If _gridLines Then
Me.Invalidate()
End If
End If
End Set
End Property
''' <summary>
''' Changes the color when item is highlighted.
''' </summary>
Public Property ItemHighlightColor() As Color
Get
Return _itemHighlightColor
End Get
Set(ByVal value As Color)
If value <> _itemHighlightColor Then
_itemHighlightColor = value
Me.Invalidate()
End If
End Set
End Property
''' <summary>
''' Changes the color when the item is not focused.
''' </summary>
Public Property ItemNotFocusedHighlighColor() As Color
Get
Return _itemNotFocusedHighlighColor
End Get
Set(ByVal value As Color)
If value <> _itemNotFocusedHighlighColor Then
_itemNotFocusedHighlighColor = value
Me.Invalidate()
End If
End Set
End Property
Private ReadOnly Property DrawCustomGridLines() As Boolean
Get
Return (_gridLines And Not _useDefaultGridLines)
End Get
End Property
Public Shadows Property GridLines() As Boolean
Get
Return _gridLines
End Get
Set(ByVal value As Boolean)
_gridLines = value
End Set
End Property
''' <summary>
''' use the default gridlines.
''' </summary>
Public Property UseDefaultGridLines() As Boolean
Get
Return _useDefaultGridLines
End Get
Set(ByVal value As Boolean)
If _useDefaultGridLines <> value Then
_useDefaultGridLines = value
End If
MyBase.GridLines = value
MyBase.OwnerDraw = Not value
End Set
End Property
#End Region
#Region " Procedures "
''' <summary>
''' Monitors when an Item is added to the ListView.
''' </summary>
Public Function AddItem(ByVal Text As String) As ListViewItem
RaiseEvent ItemAdded()
Return MyBase.Items.Add(Text)
End Function
''' <summary>
''' Monitors when an Item is removed from the ListView.
''' </summary>
Public Sub RemoveItem(ByVal Item As ListViewItem)
RaiseEvent ItemRemoved()
MyBase.Items.Remove(Item)
End Sub
Protected Overrides Sub OnDrawColumnHeader(ByVal e As DrawListViewColumnHeaderEventArgs)
e.DrawDefault = True
MyBase.OnDrawColumnHeader(e)
End Sub
Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
For Each selectedIndex As Integer In MyBase.SelectedIndices
MyBase.RedrawItems(selectedIndex, selectedIndex, False)
Next
MyBase.OnLostFocus(e)
End Sub
Protected Overrides Sub OnDrawSubItem(ByVal e As DrawListViewSubItemEventArgs)
Dim drawAsDefault As Boolean = False
Dim highlightBounds As Rectangle = Nothing
Dim highlightBrush As SolidBrush = Nothing
'FIRST DETERMINE THE COLOR
If e.Item.Selected Then
If MyBase.Focused Then
highlightBrush = New SolidBrush(_itemHighlightColor)
ElseIf HideSelection Then
drawAsDefault = True
Else
highlightBrush = New SolidBrush(_itemNotFocusedHighlighColor)
End If
Else
drawAsDefault = True
End If
If drawAsDefault Then
e.DrawBackground()
Else
'NEXT DETERMINE THE BOUNDS IN WHICH TO DRAW THE BACKGROUND
If FullRowSelect Then
highlightBounds = e.Bounds
Else
highlightBounds = e.Item.GetBounds(ItemBoundsPortion.Label)
End If
'ONLY DRAW HIGHLIGHT IN 1 OF 2 CASES
'CASE 1 - FULL ROW SELECT (AND DRAWING ANY ITEM)
'CASE 2 - NOT FULL ROW SELECT (AND DRAWING 1ST ITEM)
If FullRowSelect Then
e.Graphics.FillRectangle(highlightBrush, highlightBounds)
ElseIf e.ColumnIndex = 0 Then
e.Graphics.FillRectangle(highlightBrush, highlightBounds)
Else
e.DrawBackground()
End If
End If
e.DrawText()
If _gridLines Then
e.Graphics.DrawRectangle(New Pen(_gridLineColor), e.Bounds)
End If
If FullRowSelect Then
e.DrawFocusRectangle(e.Item.GetBounds(ItemBoundsPortion.Entire))
Else
e.DrawFocusRectangle(e.Item.GetBounds(ItemBoundsPortion.Label))
End If
MyBase.OnDrawSubItem(e)
End Sub
#End Region
#Region " ProgressBar Properties "
''' <summary>
''' Enables the drawing of a ProgressBar
''' This property should be "True" to use any of the ProgressBar properties.
''' </summary>
Public Property Enable_ProgressBar As Boolean
Get
Return _enable_progressbar
End Get
Set(ByVal value As Boolean)
Me.OwnerDraw = value
_enable_progressbar = value
End Set
End Property
''' <summary>
''' The column index to draw the ProgressBar
''' </summary>
Public Property Progressbar_Column As Integer
Get
Return _progressbar_column
End Get
Set(ByVal value As Integer)
_progressbar_column = value
End Set
End Property
''' <summary>
''' The ProgressBar progress percentage
''' </summary>
Public Property Percent As Double
Get
Return _percent
End Get
Set(ByVal value As Double)
_percent = value
End Set
End Property
''' <summary>
''' The decimal factor which should be displayed for the ProgressBar progress percentage
''' </summary>
Public Property Percent_Decimal As Short
Get
Return _percent_decimal
End Get
Set(ByVal value As Short)
_percent_decimal = value
End Set
End Property
''' <summary>
''' The Font to be used as the ProgressBar Percent text
''' </summary>
Public Property Percent_Font As Font
Get
Return _percent_font
End Get
Set(ByVal value As Font)
_percent_font = value
End Set
End Property
''' <summary>
''' The additional text to add to the ProgressBar Percent value
''' </summary>
Public Property Percent_Text As String
Get
Return _percent_text
End Get
Set(ByVal value As String)
_percent_text = value
End Set
End Property
''' <summary>
''' The ForeColor of the ProgressBar Percent Text
''' </summary>
Public Property Percent_Forecolor As Color
Get
Return _percent_forecolor.Color
End Get
Set(ByVal value As Color)
_percent_forecolor = New SolidBrush(value)
End Set
End Property
''' <summary>
''' The text allignment to use for the ProgressBar
''' </summary>
Public Property Percent_Text_Allignment As StringAlignment
Get
Return _percent_stringformat.Alignment
End Get
Set(ByVal value As StringAlignment)
_percent_stringformat.Alignment = value
End Set
End Property
''' <summary>
''' The ProgressBar BackColor
''' </summary>
Public Property ProgressBar_BackColor As Color
Get
Return _progressBar_backcolor.Color
End Get
Set(ByVal value As Color)
_progressBar_backcolor = New SolidBrush(value)
End Set
End Property
''' <summary>
''' The ProgressBar BorderColor
''' </summary>
Public Property ProgressBar_BorderColor As Color
Get
Return _progressBar_bordercolor.Color
End Get
Set(ByVal value As Color)
_progressBar_bordercolor = New Pen(value)
End Set
End Property
''' <summary>
''' The First ProgressBar Gradient color
''' </summary>
Public Property ProgressBar_FillColor1 As Color
Get
Return _progressBar_fillcolor1
End Get
Set(ByVal value As Color)
_progressBar_fillcolor1 = value
End Set
End Property
''' <summary>
''' The Last ProgressBar Gradient color
''' </summary>
Public Property ProgressBar_FillColor2 As Color
Get
Return _progressBar_fillcolor2
End Get
Set(ByVal value As Color)
_progressBar_fillcolor2 = value
End Set
End Property
#End Region
#Region " ProgressBar EventHandlers "
' ListView [DrawColumnHeader]
Public Sub Me_DrawColumnHeader(ByVal sender As Object, ByVal e As DrawListViewColumnHeaderEventArgs) Handles Me.DrawColumnHeader
e.DrawDefault = True ' Draw default ColumnHeader.
End Sub
' ListView [DrawItem]
Public Sub Me_DrawItem(ByVal sender As Object, ByVal e As DrawListViewItemEventArgs) 'Handles Me.DrawItem
e.DrawDefault = False ' Draw default main item.
End Sub
' ListView [DrawSubItem]
Public Sub Me_DrawSubItem(ByVal sender As Object, ByVal e As DrawListViewSubItemEventArgs) Handles Me.DrawSubItem
If (e.ItemState And ListViewItemStates.Selected) <> 0 Then
' Item is highlighted.
e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds)
End If
' Draw the progressbar.
If e.ColumnIndex = Me.Progressbar_Column Then
If (Not Me.Enable_ProgressBar OrElse Me.Progressbar_Column = Nothing) Then Exit Sub
' Background color of the progressbar is white.
e.Graphics.FillRectangle(Me._progressBar_backcolor, e.Bounds)
' This creates a nice color gradient to fill.
Dim brGradient As Brush = _
New System.Drawing.Drawing2D.LinearGradientBrush(New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height), _
Me.ProgressBar_FillColor1, Me.ProgressBar_FillColor2, 270, True)
' Draw the actual progressbar.
e.Graphics.FillRectangle(brGradient, _
e.Bounds.X + 1, e.Bounds.Y + 2, _
CInt(((Me.Percent) / 100) * (e.Bounds.Width - 2)), e.Bounds.Height - 3)
' Draw the percentage number and percent sign.
e.Graphics.DrawString(Me.Percent.ToString("n" & Me.Percent_Decimal) & Me.Percent_Text, _
Me.Percent_Font, Me._percent_forecolor, _
CSng(e.Bounds.X + (e.Bounds.Width / 2)), e.Bounds.Y + 3, _
_percent_stringformat)
' Draw a light gray rectangle/border around the progressbar.
e.Graphics.DrawRectangle(Me._progressBar_bordercolor, _
e.Bounds.X, e.Bounds.Y + 1, _
e.Bounds.Width - 1, e.Bounds.Height - 2)
Else
e.DrawDefault = True
End If
End Sub
#End Region
End Class
#Region " [ListView] Draw ProgressBar "
' [ [ListView] Draw ProgressBar ]
Private Listview_Column As Integer = 4 ' The column index to draw the ProgressBar
Private Percent As Double = 0 ' The progress percentage
Private Percent_DecimalFactor As Short = 1 ' Example: 0.1
Private Percent_Text As String = "% Done" ' Example: 0.1% Done
Private Percent_Forecolor As Brush = Brushes.Black
Private Percent_Font As Font = Me.Font
Private ProgressBar_BackColor As Brush = Brushes.White
Private ProgressBar_BorderColor As Pen = Pens.LightGray
Private ProgressBar_FillColor1 As Color = Color.YellowGreen
Private ProgressBar_FillColor2 As Color = Color.White
' ListView [Layout]
Private Sub ListView1_Layout(sender As Object, e As LayoutEventArgs) _
Handles ListView1.Layout
' Set Listview OwnerDraw to True, so we can draw the progressbar.
ListView1.OwnerDraw = True
End Sub
' ListView [DrawColumnHeader]
Private Sub ListView_DrawColumnHeader(ByVal sender As Object, ByVal e As DrawListViewColumnHeaderEventArgs) _
Handles ListView1.DrawColumnHeader
e.DrawDefault = True ' Draw default ColumnHeader.
End Sub
' ListView [DrawItem]
Private Sub ListView_DrawItem(ByVal sender As Object, ByVal e As DrawListViewItemEventArgs) _
Handles ListView1.DrawItem
e.DrawDefault = False ' Draw default main item.
End Sub
' ListView [DrawSubItem]
Private Sub ListView_DrawSubItem(ByVal sender As Object, ByVal e As DrawListViewSubItemEventArgs) _
Handles ListView1.DrawSubItem
If (e.ItemState And ListViewItemStates.Selected) <> 0 Then
' Item is highlighted.
e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds)
End If
' Draw the progressbar.
If e.ColumnIndex = Listview_Column Then
' Center the text in the progressbar.
Dim sf As New StringFormat
sf.Alignment = StringAlignment.Center
' Background color of the progressbar is white.
e.Graphics.FillRectangle(ProgressBar_BackColor, e.Bounds)
' Percentage of the progressbar to fill.
Dim FillPercent As Integer = CInt(((Percent) / 100) * (e.Bounds.Width - 2))
' This creates a nice color gradient to fill.
Dim brGradient As Brush = _
New System.Drawing.Drawing2D.LinearGradientBrush(New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height), _
ProgressBar_FillColor1, ProgressBar_FillColor2, 270, True)
' Draw the actual progressbar.
e.Graphics.FillRectangle(brGradient, _
e.Bounds.X + 1, e.Bounds.Y + 2, _
FillPercent, e.Bounds.Height - 3)
' Draw the percentage number and percent sign.
' NOTE: make sure that e.SubItem.Text only contains a number or an error will occur.
e.Graphics.DrawString(Percent.ToString("n" & Percent_DecimalFactor) & Percent_Text, _
Percent_Font, Percent_Forecolor, _
CSng(e.Bounds.X + (e.Bounds.Width / 2)), e.Bounds.Y + 3, _
sf)
' Draw a light gray rectangle/border around the progressbar.
e.Graphics.DrawRectangle(ProgressBar_BorderColor, _
e.Bounds.X, e.Bounds.Y + 1, _
e.Bounds.Width - 1, e.Bounds.Height - 2)
Else
e.DrawDefault = True
End If
End Sub
#End Region
#Region " Invoke Lambda "
' Create a thread.
Private t As Threading.Thread = New Threading.Thread(AddressOf UI_Thread)
' Create two Textbox.
Dim tb1 As New TextBox With {.Text = "Hello World!"}
Dim tb2 As New TextBox With {.Location = New Point(tb1.Location.X, (tb1.Location.Y + tb1.Height))}
Private Sub Form1_Load(sender As Object, e As EventArgs) _
Handles MyBase.Load
Me.Controls.AddRange({tb1, tb2}) ' Add the Textbox to the UI.
t.Start() ' Start the thread.
End Sub
Private Sub UI_Thread()
If tb2.InvokeRequired Then ' Check if invocation is required for the TextBox on the main thread.
tb2.Invoke(Sub() tb2.Text = tb1.Text) ' Then Invoke a Lambda method.
Else
tb2.Text = tb1.Text
End If
End Sub
#End Region
#Region " Delegate Example "
' Create the delegate to be able to update the TextBox.
Private Delegate Sub TextBoxUpdateUI(ByVal txt As String)
' Create a thread.
Private t As Threading.Thread = New Threading.Thread(AddressOf UI_Thread)
' Create two Textbox.
Dim tb1 As New TextBox With {.Text = "Hello World!"}
Dim tb2 As New TextBox With {.Location = New Point(tb1.Location.X, (tb1.Location.Y + tb1.Height))}
Private Sub Form1_Load(sender As Object, e As EventArgs) _
Handles MyBase.Load
Me.Controls.AddRange({tb1, tb2}) ' Add the Textbox to the UI.
t.Start() ' Start the thread.
End Sub
Private Sub UI_Thread()
If tb2.InvokeRequired Then ' Check if invocation is required for the TextBox on the main thread.
Dim tb_delegate As New TextBoxUpdateUI(AddressOf UI_Thread) ' Set the TextBox delegate.
tb2.Invoke(tb_delegate, Text) ' Invoke the delegate and the control property to update.
Else
tb2.Text = tb1.Text
End If
End Sub
#End Region
#Region " DownloadFileAsyncExtended "
#Region " Usage Examples "
' Public Class Form1
'
' ' // Instance a new Downlaoder Class
' Private WithEvents Downloader As New DownloadFileAsyncExtended
'
' ' // create a listview to update.
' Private lv As New ListView With {.View = View.Details, .Dock = DockStyle.Fill}
'
' ' // create a listview item to update.
' Private lvi As New ListViewItem
'
' ' // Set an url file to downloads.
' Dim url As String = "http://msft.digitalrivercontent.net/win/X17-58857.iso"
' Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
'
' ' Add columns to listview.
' lv.Columns.AddRange({New ColumnHeader With {.Text = "Filename"}, _
' New ColumnHeader With {.Text = "Size"}, _
' New ColumnHeader With {.Text = "Status"}, _
' New ColumnHeader With {.Text = "Completed"}, _
' New ColumnHeader With {.Text = "Progress"}, _
' New ColumnHeader With {.Text = "Speed"}, _
' New ColumnHeader With {.Text = "Time Elapsed"}, _
' New ColumnHeader With {.Text = "Time Left"} _
' })
'
' ' Add subitems to listview item.
' lvi.SubItems.AddRange({"Filename", "Size", "Status", "Completed", "Progress", "Speed", "Time Elapsed", "Time Left"})
'
' ' Add a Object tag to the listview item,
' ' so later we can reffer to this download to pause/resume or cancel it.
' lvi.Tag = Downloader
'
' ' Add the Listview control into the UI.
' Me.Controls.Add(lv)
' ' Add the Listview item into the Listview.
' lv.Items.Add(lvi)
'
' ' Set Application simultaneous internet downloads limit.
' Net.ServicePointManager.DefaultConnectionLimit = 5
'
' '// IMPORTANT !!
' '// If you don't add this line, then all events are raised on a separate thread,
' '// and you will get cross-thread errors when accessing the Listview,
' '// or other controls directly in the raised events.
' Downloader.SynchronizingObject = Me
'
' '// Update frequency.
' '// A value higher than 500 ms will prevent the DownloadProgressChanged event,
' '// from firing continuously and hogging CPU when updating the controls.
' '// If you download small files that could be downloaded within a second,
' '// then set it to "NoDelay" or the progress might not be visible.
' Downloader.ProgressUpdateFrequency = DownloadFileAsyncExtended.UpdateFrequency.MilliSeconds_500
'
' '// The method to actually download a file. The "userToken" parameter can,
' '// for example be a control you wish to update in the DownloadProgressChanged,
' '// and DownloadCompleted events. It is a ListViewItem in this example.
' Downloader.DowloadFileAsync(url, "C:\Downloaded file.iso", lvi)
'
' End Sub
' '// This event allows you to show the download progress to the user.
'
' ' e.BytesReceived = Bytes received so far.
' ' e.DownloadSpeedBytesPerSec = Download speed in bytes per second.
' ' e.DownloadTimeSeconds = Download time in seconds so far.
' ' e.ProgressPercentage = Percentage of the file downloaded.
' ' e.RemainingTimeSeconds = Remaining download time in seconds.
' ' e.TotalBytesToReceive = Total size of the file that is being downloaded.
' ' e.userToken = Usually the control(s) you wish to update.
' Private Sub DownloadProgressChanged(ByVal sender As Object, ByVal e As FileDownloadProgressChangedEventArgs) _
' Handles Downloader.DownloadProgressChanged
'
' ' Get the ListViewItem we passed as "userToken" parameter, so we can update it.
' Dim lvi As ListViewItem = DirectCast(e.userToken, ListViewItem)
'
' ' Update the ListView item subitems.
' lvi.SubItems(0).Text = url
' lvi.SubItems(1).Text = String.Format("{0:#,#} KB", (e.TotalBytesToReceive / 1024))
' lvi.SubItems(2).Text = "Downloading"
' lvi.SubItems(3).Text = String.Format("{0:#,#} KB", (e.BytesReceived / 1024))
' lvi.SubItems(4).Text = e.ProgressPercentage & "%"
' lvi.SubItems(5).Text = (e.DownloadSpeedBytesPerSec \ 1024).ToString & " kB/s"
' lvi.SubItems(6).Text = String.Format("{0}:{1}:{2}", _
' (e.DownloadTimeSeconds \ 3600).ToString("00"), _
' ((e.DownloadTimeSeconds Mod 3600) \ 60).ToString("00"), _
' (e.DownloadTimeSeconds Mod 60).ToString("00"))
' lvi.SubItems(7).Text = String.Format("{0}:{1}:{2}", _
' (e.RemainingTimeSeconds \ 3600).ToString("00"), _
' ((e.RemainingTimeSeconds Mod 3600) \ 60).ToString("00"), _
' (e.RemainingTimeSeconds Mod 60).ToString("00"))
'
' End Sub
' '// This event lets you know when the download is complete.
' '// The download finished successfully, the user cancelled the download or there was an error.
' Private Sub DownloadCompleted(ByVal sender As Object, ByVal e As FileDownloadCompletedEventArgs) _
' Handles Downloader.DownloadCompleted
'
' ' Get the ListViewItem we passed as userToken parameter, so we can update it.
' Dim lvi As ListViewItem = DirectCast(e.userToken, ListViewItem)
'
' If e.ErrorMessage IsNot Nothing Then ' Was there an error.
'
' lvi.SubItems(2).Text = "Error: " & e.ErrorMessage.Message.ToString
'
' ' Set an Error ImageKey.
' ' lvi.ImageKey = "Error"
'
' ElseIf e.Cancelled Then ' The user cancelled the download.
'
' lvi.SubItems(2).Text = "Paused"
'
' ' Set a Paused ImageKey.
' ' lvi.ImageKey = "Paused"
'
' Else ' Download was successful.
'
' lvi.SubItems(2).Text = "Finished"
'
' ' Set a Finished ImageKey.
' ' lvi.ImageKey = "Finished"
'
' End If
'
' ' Set Tag to Nothing in order to remove the wClient class instance,
' ' so this way we know we can't resume the download.
' lvi.Tag = Nothing
'
' End Sub
' '// To Resume a file:
' ' Download_Helper.Resume_Download(lvi.Tag)
' '// To pause or cancel a file:
' ' Download_Helper.PauseCancel_Download(lvi.Tag)
' End Class
#End Region
Imports System.IO
Imports System.Net
Imports System.Threading
'// This is the main download class.
Public Class DownloadFileAsyncExtended
#Region "Methods"
Private _URL As String = String.Empty
Private _LocalFilePath As String = String.Empty
Private _userToken As Object = Nothing
Private _ContentLenght As Long = 0
Private _TotalBytesReceived As Long = 0
'// Start the asynchronous download.
Public Sub DowloadFileAsync(ByVal URL As String, ByVal LocalFilePath As String, ByVal userToken As Object)
Dim Request As HttpWebRequest
Dim fileURI As New Uri(URL) '// Will throw exception if empty or random string.
'// Make sure it's a valid http:// or https:// url.
If fileURI.Scheme <> Uri.UriSchemeHttp And fileURI.Scheme <> Uri.UriSchemeHttps Then
Throw New Exception("Invalid URL. Must be http:// or https://")
End If
'// Save this to private variables in case we need to resume.
_URL = URL
_LocalFilePath = LocalFilePath
_userToken = userToken
'// Create the request.
Request = CType(HttpWebRequest.Create(New Uri(URL)), HttpWebRequest)
Request.Credentials = Credentials
Request.AllowAutoRedirect = True
Request.ReadWriteTimeout = 30000
Request.Proxy = Proxy
Request.KeepAlive = False
Request.Headers = _Headers '// NOTE: Will throw exception if wrong headers supplied.
'// If we're resuming, then add the AddRange header.
If _ResumeAsync Then
Dim FileInfo As New FileInfo(LocalFilePath)
If FileInfo.Exists Then
Request.AddRange(FileInfo.Length)
End If
End If
'// Signal we're busy downloading
_isbusy = True
'// Make sure this is set to False or the download will stop immediately.
_CancelAsync = False
'// This is the data we're sending to the GetResponse Callback.
Dim State As New HttpWebRequestState(LocalFilePath, Request, _ResumeAsync, userToken)
'// Begin to get a response from the server.
Dim result As IAsyncResult = Request.BeginGetResponse(AddressOf GetResponse_Callback, State)
'// Add custom 30 second timeout for connecting.
'// The Timeout property is ignored when using the asynchronous BeginGetResponse.
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, New WaitOrTimerCallback(AddressOf TimeoutCallback), State, 30000, True)
End Sub
'// Here we receive the response from the server. We do not check for the "Accept-Ranges"
'// response header, in order to find out if the server supports resuming, because it MAY
'// send the "Accept-Ranges" response header, but is not required to do so. This is
'// unreliable, so we'll just continue and catch the exception that will occur if not
'// supported and send it the DownloadCompleted event. We also don't check if the
'// Content-Length is '-1', because some servers return '-1', eventhough the file/webpage
'// you're trying to download is valid. e.ProgressPercentage returns '-1' in that case.
Private Sub GetResponse_Callback(ByVal result As IAsyncResult)
Dim State As HttpWebRequestState = CType(result.AsyncState, HttpWebRequestState)
Dim DestinationStream As FileStream = Nothing
Dim Response As HttpWebResponse = Nothing
Dim Duration As New Stopwatch
Dim Buffer(8191) As Byte
Dim BytesRead As Long = 0
Dim ElapsedSeconds As Long = 0
Dim DownloadSpeed As Long = 0
Dim DownloadProgress As Long = 0
Dim BytesReceivedThisSession As Long = 0
''// Get response
Response = CType(State.Request.EndGetResponse(result), HttpWebResponse)
'// Asign Response headers to ReadOnly ResponseHeaders property.
_ResponseHeaders = Response.Headers
'// If the server does not reply with an 'OK (200)' message when starting
'// the download or a 'PartialContent (206)' message when resuming.
If Response.StatusCode <> HttpStatusCode.OK And Response.StatusCode <> HttpStatusCode.PartialContent Then
'// Send error message to anyone who is listening.
OnDownloadCompleted(New FileDownloadCompletedEventArgs(New Exception(Response.StatusCode), False, State.userToken))
Return
End If
'// Create/open the file to write to.
If State.ResumeDownload Then
'// If resumed, then create or open the file.
DestinationStream = New FileStream(State.LocalFilePath, FileMode.OpenOrCreate, FileAccess.Write)
Else
'// If not resumed, then create the file, which will delete the existing file if it already exists.
DestinationStream = New FileStream(State.LocalFilePath, FileMode.Create, FileAccess.Write)
'// Get the ContentLength only when we're starting the download. Not when resuming.
_ContentLenght = Response.ContentLength
End If
'// Moves stream position to beginning of the file when starting the download.
'// Moves stream position to end of the file when resuming the download.
DestinationStream.Seek(0, SeekOrigin.End)
'// Start timer to get download duration / download speed, etc.
Duration.Start()
'// Get the Response Stream.
Using responseStream As Stream = Response.GetResponseStream()
Do
'// Read some bytes.
BytesRead = responseStream.Read(Buffer, 0, Buffer.Length)
If BytesRead > 0 Then
'// Write incoming data to the file.
DestinationStream.Write(Buffer, 0, BytesRead)
'// Count the total number of bytes downloaded.
_TotalBytesReceived += BytesRead
'// Count the number of bytes downloaded this session (Resume).
BytesReceivedThisSession += BytesRead
'// Get number of elapsed seconds (need round number to prevent 'division by zero' error).
ElapsedSeconds = CLng(Duration.Elapsed.TotalSeconds)
'// Update frequency
If (Duration.ElapsedMilliseconds - DownloadProgress) >= ProgressUpdateFrequency Then
DownloadProgress = Duration.ElapsedMilliseconds
'// Calculate download speed in bytes per second.
If ElapsedSeconds > 0 Then
DownloadSpeed = (BytesReceivedThisSession \ ElapsedSeconds)
End If
'// Send download progress to anyone who is listening.
OnDownloadProgressChanged(New FileDownloadProgressChangedEventArgs(_TotalBytesReceived, _ContentLenght, ElapsedSeconds, DownloadSpeed, State.userToken))
End If
'// Exit loop when paused.
If _CancelAsync Then Exit Do
End If
Loop Until BytesRead = 0
End Using
Try
'// Send download progress once more. If the UpdateFrequency has been set to
'// HalfSecond or Seconds, then the last percentage returned might be 98% or 99%.
'// This makes sure it's 100%.
OnDownloadProgressChanged(New FileDownloadProgressChangedEventArgs(_TotalBytesReceived, _ContentLenght, Duration.Elapsed.TotalSeconds, DownloadSpeed, State.userToken))
If _CancelAsync Then
'// Send completed message (Paused) to anyone who is listening.
OnDownloadCompleted(New FileDownloadCompletedEventArgs(Nothing, True, State.userToken))
Else
'// Send completed message (Finished) to anyone who is listening.
OnDownloadCompleted(New FileDownloadCompletedEventArgs(Nothing, False, State.userToken))
End If
Catch ex As Exception
'// Send completed message (Error) to anyone who is listening.
OnDownloadCompleted(New FileDownloadCompletedEventArgs(ex, False, State.userToken))
Finally
'// Close the file.
If DestinationStream IsNot Nothing Then
DestinationStream.Flush()
DestinationStream.Close()
DestinationStream = Nothing
End If
'// Stop and reset the duration timer.
Duration.Reset()
Duration = Nothing
'// Signal we're not downloading anymore.
_isbusy = False
End Try
End Sub
'// Here we will abort the download if it takes more than 30 seconds to connect, because
'// the Timeout property is ignored when using the asynchronous BeginGetResponse.
Private Sub TimeoutCallback(ByVal State As Object, ByVal TimedOut As Boolean)
If TimedOut Then
Dim RequestState As HttpWebRequestState = CType(State, HttpWebRequestState)
If RequestState IsNot Nothing Then
RequestState.Request.Abort()
End If
End If
End Sub
'// Cancel the asynchronous download.
Private _CancelAsync As Boolean = False
Public Sub CancelAsync()
_CancelAsync = True
End Sub
'// Resume the asynchronous download.
Private _ResumeAsync As Boolean = False
Public Sub ResumeAsync()
'// Throw exception if download is already in progress.
If _isbusy Then
Throw New Exception("Download is still busy. Use IsBusy property to check if download is already busy.")
End If
'// Throw exception if URL or LocalFilePath is empty, which means
'// the download wasn't even started yet with DowloadFileAsync.
If String.IsNullOrEmpty(_URL) AndAlso String.IsNullOrEmpty(_LocalFilePath) Then
Throw New Exception("Cannot resume a download which hasn't been started yet. Call DowloadFileAsync first.")
Else
'// Set _ResumeDownload to True, so we know we need to add
'// the Range header in order to resume the download.
_ResumeAsync = True
'// Restart (Resume) the download.
DowloadFileAsync(_URL, _LocalFilePath, _userToken)
End If
End Sub
#End Region
#Region "Properties"
Public Enum UpdateFrequency
_NoDelay = 0
MilliSeconds_100 = 100
MilliSeconds_200 = 200
MilliSeconds_300 = 300
MilliSeconds_400 = 400
MilliSeconds_500 = 500
MilliSeconds_600 = 600
MilliSeconds_700 = 700
MilliSeconds_800 = 800
MilliSeconds_900 = 900
Seconds_1 = 1000
Seconds_2 = 2000
Seconds_3 = 3000
Seconds_4 = 4000
Seconds_5 = 5000
Seconds_6 = 6000
Seconds_7 = 7000
Seconds_8 = 8000
Seconds_9 = 9000
Seconds_10 = 10000
End Enum
'// Progress Update Frequency.
Public Property ProgressUpdateFrequency() As UpdateFrequency
'// Proxy.
Public Property Proxy() As IWebProxy
'// Credentials.
Public Property Credentials() As ICredentials
'// Headers.
Public Property Headers() As New WebHeaderCollection
'// Is download busy.
Private _isbusy As Boolean = False
Public ReadOnly Property IsBusy() As Boolean
Get
Return _isbusy
End Get
End Property
'// ResponseHeaders.
Private _ResponseHeaders As WebHeaderCollection = Nothing
Public ReadOnly Property ResponseHeaders() As WebHeaderCollection
Get
Return _ResponseHeaders
End Get
End Property
'// SynchronizingObject property to marshal events back to the UI thread.
Private _synchronizingObject As System.ComponentModel.ISynchronizeInvoke
Public Property SynchronizingObject() As System.ComponentModel.ISynchronizeInvoke
Get
Return Me._synchronizingObject
End Get
Set(ByVal value As System.ComponentModel.ISynchronizeInvoke)
Me._synchronizingObject = value
End Set
End Property
#End Region
#Region "Events"
Public Event DownloadProgressChanged As EventHandler(Of FileDownloadProgressChangedEventArgs)
Private Delegate Sub DownloadProgressChangedEventInvoker(ByVal e As FileDownloadProgressChangedEventArgs)
Protected Overridable Sub OnDownloadProgressChanged(ByVal e As FileDownloadProgressChangedEventArgs)
If Me.SynchronizingObject IsNot Nothing AndAlso Me.SynchronizingObject.InvokeRequired Then
'Marshal the call to the thread that owns the synchronizing object.
Me.SynchronizingObject.Invoke(New DownloadProgressChangedEventInvoker(AddressOf OnDownloadProgressChanged), _
New Object() {e})
Else
RaiseEvent DownloadProgressChanged(Me, e)
End If
End Sub
Public Event DownloadCompleted As EventHandler(Of FileDownloadCompletedEventArgs)
Private Delegate Sub DownloadCompletedEventInvoker(ByVal e As FileDownloadCompletedEventArgs)
Protected Overridable Sub OnDownloadCompleted(ByVal e As FileDownloadCompletedEventArgs)
If Me.SynchronizingObject IsNot Nothing AndAlso Me.SynchronizingObject.InvokeRequired Then
'Marshal the call to the thread that owns the synchronizing object.
Me.SynchronizingObject.Invoke(New DownloadCompletedEventInvoker(AddressOf OnDownloadCompleted), _
New Object() {e})
Else
RaiseEvent DownloadCompleted(Me, e)
End If
End Sub
#End Region
End Class
Public Class Download_Helper
''' <summary>
''' Resumes a file download.
''' </summary>
Public Shared Sub Resume_Download(ByVal File As Object)
Dim Downloader As DownloadFileAsyncExtended
Try
Downloader = DirectCast(File, DownloadFileAsyncExtended)
Downloader.CancelAsync()
Catch ex As Exception
MessageBox.Show(ex.Message, Nothing, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
''' <summary>
''' Pauses or cancel a file download.
''' </summary>
Public Shared Sub PauseCancel_Download(ByVal File As Object)
Dim Downloader As DownloadFileAsyncExtended
Try
Downloader = DirectCast(File, DownloadFileAsyncExtended)
If Not Downloader.IsBusy Then
Downloader.ResumeAsync()
End If
Catch ex As Exception
MessageBox.Show(ex.Message, Nothing, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
End Class
'// This class is passed as a parameter to the GetResponse Callback,
'// so we can work with the data in the Response Callback.
Public Class HttpWebRequestState
Private _LocalFilePath As String
Private _Request As HttpWebRequest
Private _ResumeDownload As Boolean
Private _userToken As Object
Public Sub New(ByVal LocalFilePath As String, ByVal Request As HttpWebRequest, ByVal ResumeDownload As Boolean, ByVal userToken As Object)
_LocalFilePath = LocalFilePath
_Request = Request
_ResumeDownload = ResumeDownload
_userToken = userToken
End Sub
Public ReadOnly Property LocalFilePath() As String
Get
Return _LocalFilePath
End Get
End Property
Public ReadOnly Property Request() As HttpWebRequest
Get
Return _Request
End Get
End Property
Public ReadOnly Property ResumeDownload() As Boolean
Get
Return _ResumeDownload
End Get
End Property
Public ReadOnly Property userToken() As Object
Get
Return _userToken
End Get
End Property
End Class
'// This is the data returned to the user for each download in the
'// Progress Changed event, so you can update controls with the progress.
Public Class FileDownloadProgressChangedEventArgs
Inherits EventArgs
Private _BytesReceived As Long
Private _TotalBytesToReceive As Long
Private _DownloadTime As Long
Private _DownloadSpeed As Long
Private _userToken As Object
Public Sub New(ByVal BytesReceived As Long, ByVal TotalBytesToReceive As Long, ByVal DownloadTime As Long, ByVal DownloadSpeed As Long, ByVal userToken As Object)
_BytesReceived = BytesReceived
_TotalBytesToReceive = TotalBytesToReceive
_DownloadTime = DownloadTime
_DownloadSpeed = DownloadSpeed
_userToken = userToken
End Sub
Public ReadOnly Property BytesReceived() As Long
Get
Return _BytesReceived
End Get
End Property
Public ReadOnly Property TotalBytesToReceive() As Long
Get
Return _TotalBytesToReceive
End Get
End Property
Public ReadOnly Property ProgressPercentage() As Long
Get
If _TotalBytesToReceive > 0 Then
Return Math.Ceiling((_BytesReceived / _TotalBytesToReceive) * 100)
Else
Return -1
End If
End Get
End Property
Public ReadOnly Property DownloadTimeSeconds() As Long
Get
Return _DownloadTime
End Get
End Property
Public ReadOnly Property RemainingTimeSeconds() As Long
Get
If DownloadSpeedBytesPerSec > 0 Then
Return Math.Ceiling((_TotalBytesToReceive - _BytesReceived) / DownloadSpeedBytesPerSec)
Else
Return 0
End If
End Get
End Property
Public ReadOnly Property DownloadSpeedBytesPerSec() As Long
Get
Return _DownloadSpeed
End Get
End Property
Public ReadOnly Property userToken() As Object
Get
Return _userToken
End Get
End Property
End Class
'// This is the data returned to the user for each download in the
'// Download Completed event, so you can update controls with the result.
Public Class FileDownloadCompletedEventArgs
Inherits EventArgs
Private _ErrorMessage As Exception
Private _Cancelled As Boolean
Private _userToken As Object
Public Sub New(ByVal ErrorMessage As Exception, ByVal Cancelled As Boolean, ByVal userToken As Object)
_ErrorMessage = ErrorMessage
_Cancelled = Cancelled
_userToken = userToken
End Sub
Public ReadOnly Property ErrorMessage() As Exception
Get
Return _ErrorMessage
End Get
End Property
Public ReadOnly Property Cancelled() As Boolean
Get
Return _Cancelled
End Get
End Property
Public ReadOnly Property userToken() As Object
Get
Return _userToken
End Get
End Property
End Class
#End Region
Public Class Form1
' // Instance a new Downlaoder Class
Private WithEvents Downloader As New DownloadFileAsyncExtended
' // create a listview to update.
Private lv As New ListView With {.View = View.Details, .Dock = DockStyle.Fill}
' // create a listview item to update.
Private lvi As New ListViewItem
'// Set an url file to downloads.
Dim url As String = "http://msft.digitalrivercontent.net/win/X17-58857.iso"
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
' Add columns to listview.
lv.Columns.AddRange({New ColumnHeader With {.Text = "Filename"}, _
New ColumnHeader With {.Text = "Size"}, _
New ColumnHeader With {.Text = "Status"}, _
New ColumnHeader With {.Text = "Completed"}, _
New ColumnHeader With {.Text = "Progress"}, _
New ColumnHeader With {.Text = "Speed"}, _
New ColumnHeader With {.Text = "Time Elapsed"}, _
New ColumnHeader With {.Text = "Time Left"} _
})
' Add subitems to listview item.
lvi.SubItems.AddRange({"Filename", "Size", "Status", "Completed", "Progress", "Speed", "Time Elapsed", "Time Left"})
' Add a Object tag to the listview item,
' so later we can reffer to this download to pause/resume or cancel it.
lvi.Tag = Downloader
' Add the Listview control into the UI.
Me.Controls.Add(lv)
' Add the Listview item into the Listview.
lv.Items.Add(lvi)
' Set Application simultaneous internet downloads limit.
Net.ServicePointManager.DefaultConnectionLimit = 5
'// IMPORTANT !!
'// If you don't add this line, then all events are raised on a separate thread,
'// and you will get cross-thread errors when accessing the Listview,
'// or other controls directly in the raised events.
Downloader.SynchronizingObject = Me
'// Update frequency.
'// A value higher than 500 ms will prevent the DownloadProgressChanged event,
'// from firing continuously and hogging CPU when updating the controls.
'// If you download small files that could be downloaded within a second,
'// then set it to "NoDelay" or the progress might not be visible.
Downloader.ProgressUpdateFrequency = DownloadFileAsyncExtended.UpdateFrequency.MilliSeconds_500
'// The method to actually download a file. The "userToken" parameter can,
'// for example be a control you wish to update in the DownloadProgressChanged,
'// and DownloadCompleted events. It is a ListViewItem in this example.
Downloader.DowloadFileAsync(url, "C:\Downloaded file.iso", lvi)
End Sub
'// This event allows you to show the download progress to the user.
'
' e.BytesReceived = Bytes received so far.
' e.DownloadSpeedBytesPerSec = Download speed in bytes per second.
' e.DownloadTimeSeconds = Download time in seconds so far.
' e.ProgressPercentage = Percentage of the file downloaded.
' e.RemainingTimeSeconds = Remaining download time in seconds.
' e.TotalBytesToReceive = Total size of the file that is being downloaded.
' e.userToken = Usually the control(s) you wish to update.
Private Sub DownloadProgressChanged(ByVal sender As Object, ByVal e As FileDownloadProgressChangedEventArgs) _
Handles Downloader.DownloadProgressChanged
' Get the ListViewItem we passed as "userToken" parameter, so we can update it.
Dim lvi As ListViewItem = DirectCast(e.userToken, ListViewItem)
' Update the ListView item subitems.
lvi.SubItems(0).Text = url
lvi.SubItems(1).Text = String.Format("{0:#,#} KB", (e.TotalBytesToReceive / 1024))
lvi.SubItems(2).Text = "Downloading"
lvi.SubItems(3).Text = String.Format("{0:#,#} KB", (e.BytesReceived / 1024))
lvi.SubItems(4).Text = e.ProgressPercentage & "%"
lvi.SubItems(5).Text = (e.DownloadSpeedBytesPerSec \ 1024).ToString & " kB/s"
lvi.SubItems(6).Text = String.Format("{0}:{1}:{2}", _
(e.DownloadTimeSeconds \ 3600).ToString("00"), _
((e.DownloadTimeSeconds Mod 3600) \ 60).ToString("00"), _
(e.DownloadTimeSeconds Mod 60).ToString("00"))
lvi.SubItems(7).Text = String.Format("{0}:{1}:{2}", _
(e.RemainingTimeSeconds \ 3600).ToString("00"), _
((e.RemainingTimeSeconds Mod 3600) \ 60).ToString("00"), _
(e.RemainingTimeSeconds Mod 60).ToString("00"))
End Sub
'// This event lets you know when the download is complete.
'// The download finished successfully, the user cancelled the download or there was an error.
Private Sub DownloadCompleted(ByVal sender As Object, ByVal e As FileDownloadCompletedEventArgs) _
Handles Downloader.DownloadCompleted
' Get the ListViewItem we passed as userToken parameter, so we can update it.
Dim lvi As ListViewItem = DirectCast(e.userToken, ListViewItem)
If e.ErrorMessage IsNot Nothing Then ' Was there an error.
lvi.SubItems(2).Text = "Error: " & e.ErrorMessage.Message.ToString
' Set an Error ImageKey.
' lvi.ImageKey = "Error"
ElseIf e.Cancelled Then ' The user cancelled the download.
lvi.SubItems(2).Text = "Paused"
' Set a Paused ImageKey.
' lvi.ImageKey = "Paused"
Else ' Download was successful.
lvi.SubItems(2).Text = "Finished"
' Set a Finished ImageKey.
' lvi.ImageKey = "Finished"
End If
' Set Tag to Nothing in order to remove the wClient class instance,
' so this way we know we can't resume the download.
lvi.Tag = Nothing
End Sub
' Private Sub Button_Resume_Click(sender As Object, e As EventArgs) Handles Button_Resume.Click
'// To Resume a file:
' Download_Helper.Resume_Download(lvi.Tag)
'End Sub
'Private Sub Button_Pause_Click(sender As Object, e As EventArgs) Handles Button_Pause.Click
'// To pause or cancel a file:
' Download_Helper.PauseCancel_Download(lvi.Tag)
'End Sub
End Class