Поместите в задачу длительный метод, покажите новую форму и закройте ее после завершения задачи.
У моего приложения есть какой-то давно работающий метод, который требует некоторого времени для завершения, поэтому я решил перенести его в отдельную задачу, а затем покажу некоторую новую форму как ShowDialog
внутри которого помещена анимация песочных часов, а затем эта форма должна быть закрыта, когда задача завершит работу. В тот момент ситуация такова, что моя новая форма ожидания совсем не собирается закрываться, она просто появляется и остается. Я где-то читал, что его, потому что ShowDialog
в этом случае ничего не вернется, поэтому Close
никогда не будет достигнут до тех пор, пока пользователь не нажмет кнопку Закрыть в форме вручную, но насколько это возможно, как если бы я положил form.Close
оно должно быть таким же, как пользователь нажимает на эту форму. Пожалуйста, объяснений и поддержки здесь, что следует изменить, чтобы достичь цели. Ниже мой код.
Основная форма:
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)
Вариант 2: (не работает, почему??)
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: Это было первоначально:
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://stackru.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
2 ответа
У вас уже есть ответ здесь:
Отображение прогресса переноса сборки WinSCP .NET на панели прогресса WinForm
Проще говоря, я просто извлекаю соответствующую часть:
- Вам необходимо закрыть форму в конце задания.
- Поскольку задача выполняется в фоновом потоке, вам необходимо использовать
.Invoke
метод для вызова закрытия в потоке GUI.
Простая реализация выглядит так:
' 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
Что касается универсального обработчика без задач, это то, как я добился в одном из приложений некоторое время назад
Добавить новую форму (frmProgress)
Добавьте изображение GIF песочных часов (picProgress) в центр этой формы
Установите следующие свойства формы (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
Центрировать изображение в форме по событию изменения размера, если требуется
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
Загрузите форму перед началом обработки (НЕ используйте ShowDialog ())
frmProgress.Show()'DO NOT use ShowDialog()
Инициируйте вашу обработку
Скрыть форму прогресса после выполнения задачи
frmProgress.Hide()