Отображение прогресса переноса сборки WinSCP .NET на панели прогресса WinForm
Есть какая-то основная форма, в которой я называю загрузку файлов с FTP. Когда эта операция поднята, я хочу видеть новую форму как ShowDialog
и индикатор прогресса на нем, который будет отображаться в это время, затем покажите прогресс и закройте новую форму и вернитесь к основной форме. Мой код работает, однако, когда он будет обрабатываться, моя основная форма зависает, и через некоторое время появляется новая форма, а затем закрывается. Что я хотел бы исправить, так это показать эту новую форму, которая будет показана сразу после выполнения процесса. Можете ли вы взглянуть и сказать мне, что не так?
Это из моей основной формы процесс загрузки называется:
Dim pro As New FrmProgressBarWinscp(WinScp, myremotePicturePath, ladujZdjeciaPath, True)
FrmProgressBarWinscp
как следует:
Public Class FrmProgressBarWinscp
Property _winScp As WinScpOperation
Property _remotePicture As String
Property _ladujZdjecia As String
Property _removesource As String
Public Sub New()
InitializeComponent()
End Sub
Sub New(winscp As WinScpOperation, remotePicture As String, ladujzdjecia As String, removesource As Boolean)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_winScp = winscp
_remotePicture = remotePicture
_ladujZdjecia = ladujzdjecia
_removesource = removesource
ShowDialog()
End Sub
Sub Run()
Try
Cursor = Cursors.WaitCursor
_winScp.GetFile(_remotePicture, _ladujZdjecia, _removesource)
ProgressBar1.Minimum = 0
ProgressBar1.Maximum = 1
ProgressBar1.Value = 0
Do
ProgressBar1.Value = WinScpOperation._lastProgress
ProgressBar1.Refresh()
Loop Until ProgressBar1.Value = 1
Cursor = Cursors.Default
'Close()
Catch ex As Exception
Finally
If _winScp IsNot Nothing Then
_winScp.SessionDispose()
End If
System.Threading.Thread.Sleep(10000)
Close()
End Try
End Sub
Private Sub FrmProgressBarWinscp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Run()
End Sub
End Class
Winscp мой собственный класс и используемые методы:
...
Function GetFile(source As String, destination As String, Optional removeSource As Boolean = False)
Dim result As Boolean = True
Try
session.GetFiles(source, destination, removeSource).Check()
Catch ex As Exception
result = False
End Try
Return result
End Function
Private Shared Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs)
'Print transfer progress
_lastProgress = e.FileProgress
End Sub
Public Shared _lastProgress As Integer
...
Дальнейшее обсуждение № 3:
Main form:
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
Return WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True)
End Function)
Dim forma As New FrmProgressBar
forma.ShowDialog()
Форма индикатора выполнения:
Public Class FrmProgressBar
Public Sub New()
InitializeComponent()
End Sub
Sub Run()
Try
Do
ProgressBar1.Value = WinScpOperation._lastProgress
ProgressBar1.Refresh()
Loop Until ProgressBar1.Value = 1
Cursor = Cursors.Default
Catch ex As Exception
Finally
MsgBox("before sleep")
System.Threading.Thread.Sleep(10000)
MsgBox("after sleep sleep")
Close()
End Try
End Sub
Private Sub FrmProgressBarWinscp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Run()
End Sub
End Class
Точка №. 4:
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
Return WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True)
End Function)
Dim pic As New Waiting
pic.ShowDialog()
Task.WaitAll(tsk)
pic.Close()
Пункт 5:
Dim pic As New Waiting
pic.ShowDialog()
Dim tsk As Task = Task.Factory.StartNew(Sub() WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, pic, True))
Task.WaitAll(tsk)
'pic.Close()
В каком-то другом классе (возможно, не упоминался до того, как этот метод был помещен в другой класс - мой пользовательский)
Public Function GetFile(source As String, destination As String, formclose As InvokeCloseForm, Optional removeSource As Boolean = False) As Boolean
Dim result As Boolean = True
Try
session.GetFiles(source, destination, removeSource).Check()
Catch ex As Exception
result = False
End Try
formclose.RUn()
Return result
End Function
Интерфейс:
Public Interface InvokeCloseForm
Sub RUn()
End Interface
Форма ожидания:
Public Class Waiting
Implements InvokeCloseForm
Public Sub RUn() Implements InvokeCloseForm.RUn
Me.Close()
End Sub
End Class
1 ответ
Session.GetFiles
метод в блокировке.
Это означает, что он возвращается только после завершения передачи.
Решение состоит в том, чтобы:
Запустите передачу WinSCP (
Session.GetFiles
) в отдельном потоке, чтобы не блокировать поток GUI.Для этого посмотрите пользовательский интерфейс приложения WinForm во время длительной работы.
Обрабатывать
Session.FileTransferProgress
событиеОбратите внимание, что обработчик событий будет вызываться в фоновом потоке, поэтому вы не можете обновить индикатор выполнения непосредственно из обработчика. Вы должны использовать
Control.Invoke
чтобы убедиться, что индикатор выполнения обновляется в потоке графического интерфейса.Для этого смотрите Как обновить GUI из другого потока в C#?
Тривиальная реализация выглядит так:
Public Class ProgressDialog1 Private Sub ProgressDialog1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Run download on a separate thread ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Download)) End Sub Private Sub Download(stateInfo As Object) ' Setup session options Dim mySessionOptions As New SessionOptions With mySessionOptions ... End With Using mySession As Session = New Session AddHandler mySession.FileTransferProgress, AddressOf SessionFileTransferProgress ' Connect mySession.Open(mySessionOptions) mySession.GetFiles(<Source>, <Destination>).Check() End Using ' Close form (invoked on GUI thread) Invoke(New Action(Sub() Close())) End Sub Private Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs) ' Update progress bar (on GUI thread) ProgressBar1.Invoke(New Action(Of Double)(AddressOf UpdateProgress), e.OverallProgress) End Sub Private Sub UpdateProgress(progress As Double) ProgressBar1.Value = progress * 100 End Sub End Class
Вы можете отключить форму выполнения (или ее части) во время операции, если хотите запретить пользователю выполнять некоторые операции.
Использовать
.Enabled
свойство формы или контроля (ов).
Более простое, но хакерское и вообще не рекомендуемое решение - это вызвать Application.DoEvents
метод из вашего существующего SessionFileTransferProgress
обработчик.
И, конечно же, вы должны обновить индикатор выполнения из SessionFileTransferProgress
также.
Private Shared Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs)
'Print transfer progress
ProgressBar1.Value = e.FileProgress
Application.DoEvents
End Sub
И индикатор выполнения .Minimum
а также .Maximum
должен быть установлен до Session.GetFiles
,
Но не делай этого! Это неправильный подход.
И все же, вам нужно отключить формы / элементы управления так же, как в правильном решении выше.