2015-10-09 5 views
0

У моего приложения есть некоторый длинный метод, который занимает некоторое время, чтобы быть завершенным, поэтому я решил вставить его в отдельную задачу, а затем показать некоторые новые форму как ShowDialog, внутри которой размещена анимация песочных часов, а затем эта форма должна быть закрыта, когда задача завершила работу. В тот момент ситуация заключается в том, что моя новая форма ожидания не собирается закрываться при ее просто появлении и пребывании. Я где-то читал, потому что ShowDialog в этом случае ничего не вернет, поэтому Close никогда не будет достигнут, пока пользователь не нажмет Закрыть вручную по форме, но как его возможно, как если бы я положил form.Close, он должен быть таким же, как пользователь будет нажимать на эту форму , Пожалуйста, объясните и поддержите здесь, что нужно изменить для достижения цели. Ниже моего кода.Положите метод long running в задачу, показывая новую форму и закрыв ее после завершения задачи

Главная форма:

WinScp = New WinScpOperation("ftp", "myserver", "login", "password", 21, 0) 

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() 'show waiting form 

Task.WaitAll(tsk) 'waiting on task to be finalized 

pic.Close() 'close waiting form 
... 

Ожидание формы (ничего, кроме песочных GIF)

Public Class Waiting 
End Class 

Дальнейшее обсуждение # 1:

Вариант 1: (ваша рабочая версия)

Dim pic As New Waiting 

          Dim tsk As Task(Of Boolean) = 
    Task.Factory.StartNew(Of Boolean)(
     Function() 
      ' Run lenghty task 
      Dim Result As Boolean = WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True) 
      ' Close form once done (on GUI thread) 
      pic.Invoke(New Action(Sub() pic.Close())) 
      Return Result 
     End Function) 

          ' Show the form 
          pic.ShowDialog() 
          Task.WaitAll(tsk) 

Option2: (не работает, почему ??)

Dim pic As New Waiting 

          Dim tsk As Task(Of Boolean) = 
    Task.Factory.StartNew(Of Boolean)(
     Function() 
      ' Run lenghty task 
      Dim Result As Boolean = WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True) 

      Return Result 
     End Function) 

          ' Show the form 
          pic.ShowDialog() 
          Task.WaitAll(tsk) 
    ' Close form once done (on GUI thread) 
      pic.Invoke(New Action(Sub() pic.Close())) 

Дополнительный вопрос:

     Dim pic As New Waiting 

         Dim tsk As Task(Of Boolean) = 
Task.Factory.StartNew(Of Boolean)(
    Function() 
     ' Run lenghty task 
     Dim Result As Boolean = WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True) 
     ' Close form once done (on GUI thread) 
     pic.Invoke(New Action(Sub() pic.Close())) 
     Return Result 
    End Function) 

         ' Show the form 
         pic.ShowDialog() 
         Task.WaitAll(tsk) 

         If tsk.Result Then 'if return value is true 
          'Do something when file was downloaded correctly 
         Else 
          'Do something when file was NOT downloaded 
         End If 

Дополнительный # 2: Это было oryginally:

  If WinScp.GetFile(lsbxPicPaths.SelectedItem, temp_dir & "\" & Path.GetFileName(lsbxPicPaths.SelectedItem), False) Then 
       temp_pic = temp_dir & "\" & Path.GetFileName(lsbxPicPaths.SelectedItem) 
      End If 

Я реализовал наше решение:

Dim pic As New Waiting 


           Dim tsk As Task(Of Boolean) = 
       Task.Factory.StartNew(Of Boolean)(
        Function() 
       Run lenghty task 
         Dim Result As Boolean = WinScp.GetFile(lsbxPicPaths.SelectedItem, temp_dir & "\" & Path.GetFileName(lsbxPicPaths.SelectedItem), False) 
        ' Close form once done (on GUI thread) 
         pic.Invoke(New Action(Sub() pic.Close())) 
         Return Result 
       End Function) 

          ' Show the form 
           pic.ShowDialog() 
          Task.WaitAll(tsk) 

        If tsk.Result Then 'if return value is true 

            temp_pic = temp_dir & "\" & Path.GetFileName(lsbxPicPaths.SelectedItem) 
       '    Else 

           End If 

       '************************************* 

Решение к выше: понятия не имею, почему, когда определены две переменные вместо непосредственно положить его в аргументы GetFile решить, потому что ранее также не было переменных и работает. Может ли кто-нибудь объяснить это поведение?

   Dim remotefile As String = lsbxPicPaths.SelectedItem 
       Dim temp_file As String = temp_dir & "\" & Path.GetFileName(lsbxPicPaths.SelectedItem) 


       'http://stackoverflow.com/questions/33030706/put-long-running-method-into-task-showing-new-form-meantime-and-closing-it-once 
       Dim pic2 As New Waiting 



       Dim tsk2 As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function() 

                        'Run lenghty task 

                        Dim Result As Boolean = WinScp.GetFile(remotefile, temp_file, False) 
                        'Close form once done (on GUI thread) 
                        pic2.Invoke(New Action(Sub() pic2.Close())) 
                        Return Result 
                       End Function) 
       pic2.ShowDialog() 
       Task.WaitAll(tsk2) 


       If tsk2.Result = True Then 
        MsgBox("GetFile zwrocilo true") 
        temp_pic = temp_dir & "\" & Path.GetFileName(lsbxPicPaths.SelectedItem) 
       End If 

ответ

1

У вас уже есть ответ здесь:
Showing WinSCP .NET assembly transfer progress on WinForm's progress bar

положить его просто, я просто извлекая соответствующую часть:

  • Вам нужно, чтобы закрыть форму в конце задачи.
  • Поскольку задача выполняется на фоновом потоке, вам нужно использовать .Invoke method, чтобы вызвать закрытие по потоку графического интерфейса.

Простая реализация как:

' Create the form before the task, so that we can reference it in the task 
Dim pic As New Waiting 

Dim tsk As Task(Of Boolean) = 
    Task.Factory.StartNew(Of Boolean)(
     Function() 
      ' Run lenghty task 
      Dim Result As Boolean = 
       WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True) 
      ' Close form once done (on GUI thread) 
      pic.Invoke(New Action(Sub() pic.Close())) 
      Return Result 
     End Function) 

' Show the form 
pic.ShowDialog() 

Внутри WinForms Form работает как:

Class Form          

    Private closed as Boolean     

    Function ShowDialog       

     While Not closed       

      If ' X button clicked     
       Close       
      End IF        

      If ' anything in the Invoke queue  
       ' Get action from the Invoke queue 
       ' Run the action     
       ' In our case the "action" is .Close 
      End If        

      ' Process message queue (mouse clicks, key presses, draw form) 

     End While        

    End Sub          

    Sub Close         
     closed = True       
    End Sub          

    Sub Invoke(action)       
     ' Add action to invoke queue    
    End Sub          

End Class          
+0

отличная работа !! Во всяком случае, я не могу понять, как это работает - посмотрите мой главный пост, пожалуйста. Вариант 1 - ваш код - никаких проблем. Вариант 2 - почему, когда move вызывает внешнюю разделенную нить, он не будет работать, так же, как если бы я просто поместил pic.Close? Не могу понять, почему я должен назвать это из второй разделенной нити? – Arie

+1

Поскольку метод ShowDialog является методом блокировки. Он работает до тех пор, пока форма открывается. Не похоже, что форма и код продолжаются на следующей строке. Он останавливается на вызове ShowDialog, и вы не можете ничего сделать в этом (GUI) потоке. 'ShowDialog' запускает цикл внутри. Поэтому вам нужно нарушить цикл извне, вызвав '.Close'. –

+0

так просто говорить, что я не могу просто поместить pic.Close или pic.Invoke (новое действие (Sub() pic.Close())) из того же самого потока gui правильно (опция 2)? Я должен делать это из разделенной нити, как в нашем случае tsk do? – Arie

1

Как родового обработчика без задач, это то, как я достиг в одном приложений некогда

  1. Добавить новую форму (frmProgress)

  2. Добавить песочное GIF изображение (picProgress) к центру этой формы

  3. Установить следующий вид (frmProgress) свойства либо в графическом интерфейсе или в коде на событиях нагрузки :

    Private Sub frmProgress_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
        FormBorderStyle = FixedSingle 
        Opacity = 0.5R 
        ShowInTaskbar = False 
        TopMost = True 
        WindowState = Maximized 
    End Sub 
    
  4. центр изображения в форме на событие изменения размера, если требуется

    Private Sub frmProgress_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize 
        picProgress.Left = CInt(Me.Width/2 - picProgress.Width/2) 
        picProgress.Top = CInt(Me.Height/2 - picProgress.Height/2) 
    End Sub 
    
  5. Загрузите форму до начала обработки вашего (НЕ используйте ShowDialog())

    frmProgress.Show()'DO NOT use ShowDialog() 
    
  6. Инициировать ваша обработка

  7. Скрыть форму прогресса после того, как задача выполнена

    frmProgress.Hide()