将 long 运行 方法放入任务中,同时显示新表单并在任务完成后关闭它
Put long running method into task, showing new form meantime and closing it once the task completes
我的应用程序有一些很长的 运行 方法,需要一些时间才能完成,因此我决定将它推到单独的任务中,同时显示一些新的形式 ShowDialog
,里面放着沙漏动画,然后在任务完成时关闭此表单。在那一刻的情况是我的新等待表格根本不会关闭它只是出现并留下来。我在某处读到它是因为 ShowDialog
在那种情况下不会 return 什么都没有,这就是为什么 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)
'
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
这里已经有了答案:
为了简单起见,我只是提取相关部分:
- 您需要在任务结束时关闭表单。
- 由于任务在后台线程上运行,您需要使用
.Invoke
method 在 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) 添加到此表单的中心
在 GUI 或加载事件代码中设置以下表单 (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()
我的应用程序有一些很长的 运行 方法,需要一些时间才能完成,因此我决定将它推到单独的任务中,同时显示一些新的形式 ShowDialog
,里面放着沙漏动画,然后在任务完成时关闭此表单。在那一刻的情况是我的新等待表格根本不会关闭它只是出现并留下来。我在某处读到它是因为 ShowDialog
在那种情况下不会 return 什么都没有,这就是为什么 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)
'
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
这里已经有了答案:
为了简单起见,我只是提取相关部分:
- 您需要在任务结束时关闭表单。
- 由于任务在后台线程上运行,您需要使用
.Invoke
method 在 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) 添加到此表单的中心
在 GUI 或加载事件代码中设置以下表单 (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()