我认为这实际上并没有发生,但似乎我的WPF应用程序(窗口)没有异步调用Sub,或者看起来像这样的东西......用例非常简单:
wpfw = WPF窗口
StatusLeft = wpfw上的文本框
cmds =在wpfw类中实例化的命令类,用于存储所有窗口命令(subs)。该 wpfw实例在构造函数中传递给它。
UpdateStatusLeft = cmds中的Sub,如下所示:
Private Sub UpdateStatusLeft(UpdateText As String)
Try
Me.wpfw.Dispatcher.Invoke(CType(Sub() Me.wpfw.StatusLeft.Text = UpdateText, Action))
Catch ex As Exception
[...]
End Try
End Sub
以上工作,但只在cmds中长时间运行的子菜单完成后才更新主窗口。调用长时间运行的命令并不特别:
(XAML)
<MenuItem Header="Process Files" Click="mnuReference_ProcessFiles"/>
在wpfw中,点击的处理程序( mnuReference_ProcessFiles )是这样的:
Private Sub mnuReference_ProcessFiles(sender As Object, e As RoutedEventArgs)
Me.cmds.ParseFiles()
End Sub
现在,只要wpfw,cmds就会被实例化,而它所指向的sub( mnuReference_ProcessFiles )就像这样:
Public Sub ParseFiles() Implements Icmds.ParseFiles
Try
Dim fu As FileUtils = New FileUtils()
Me.UpdateStatusLeft("Starting Batch 1...")
ipu.ParseFile(".\batch1")
Me.UpdateStatusLeft("Starting Batch 2...")
ipu.ParseFile(".\batch2")
[...]
上面,“ Me.UpdateStatusLeft ”位于cmds类中。实际上,我在主窗口调用的每个类中都放置了一个Sub UpdateStatusLeft(包括它自己的类!),然后将wpfc 实例传递给每个命令/处理类。
如果你试图直接更新textarea而不是wpfw的另一个线程/类,你会得到一个线程错误 - 这就是为什么我使用 Dispatcher.Invoke(...
净度:
这些命令都按预期启动,并且做得很好。这从来都不是问题。
问题是试图找到一种方法来更新顶级/原始UI线程的textarea,因为这些任务进展,因此用户不会入睡或认为程序已崩溃等。
答案 0 :(得分:3)
主应用程序调度程序使用UI线程,因此长时间运行的进程仍将锁定UI线程
典型的解决方案是在后台线程中运行长时间运行的进程,然后使用调度程序在主线程完成后更新UI对象。
或者,如果您使用类似Task Parallel Library的内容,它允许您为UI线程安排任务,并完全绕过调度程序。这是一个例子:
Task.Factory
.StartNew(() =>
{
// This runs in a background thread
return GetLongRunningProcessResults();
})
.ContinueWith.StartNew((t) =>
{
// This runs in the UI thread because of the
// TaskScheduler.FromCurrentSynchronizationContext parameter
UpdateUI(t.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
答案 1 :(得分:0)
在Tasks.Run的通话中将代码包裹在ParseFiles
。
如果您希望应用程序保持响应,则必须在主线程之外的另一个线程中执行密集型任务。