Отображение прогресса переноса сборки 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,

Но не делай этого! Это неправильный подход.

И все же, вам нужно отключить формы / элементы управления так же, как в правильном решении выше.

Другие вопросы по тегам