访问一个WPF的FlowDocument在后台在后台进程中
我的问题涉及访问UI对象,在WPF背景访问一个WPF的FlowDocument。我看过几十个示例应用程序,所有这些应用程序都很简单,易于使用,其中95%告诉你如何显示进度条。这不是我想要的......
我的问题是这样的:我想通过访问RichTextBox中的FlowDocument来执行长任务(或许多长任务)。确切的任务在这里没有关系,但是一个例子可能是扫描整个文档,并计算特定单词出现的次数,或者有多少红色字符......。在长文档中,这些可能是相当耗时的任务,并且如果在前台完成,将会大大限制UI并使其无响应。我只想解析FlowDocument;我不想对它做任何更改。
所以这就是我想要做的事情。显而易见的解决方案是在后台进行,但问题是......怎么做?我已经实现了似乎是一个答案,但它只是对我来说“不适合”,这就是为什么我在这里寻求帮助。
我跟随“解决方案”
我的“解决方案”使用它调用UI对象的调度,以确保正确的线程访问一个BackgroundWorker ......和“出现”它做的工作。但是这样做吗?.............. 我已经大大简化了我的“解决方案”,使它变得简单(我希望)遵循我所做的...。
WithEvents worker As BackgroundWorker
Private Delegate Sub DelegateSub()
Private theDocument As FlowDocument
''' <summary>
''' Triggers the background task. Can call from anywhere in main code blocks
''' </summary>
Private Sub StartTheBackgroundTask()
worker = New BackgroundWorker
worker.RunWorkerAsync()
End Sub
''' <summary>
''' In the background, hands the job over to the UI object's Dispatcher
''' </summary>
Private Sub HandleWorkerDoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
Dim priority As System.Windows.Threading.DispatcherPriority
Dim theLongRunningTask As DelegateSub
'(1) Define a delegate for the Dispatcher to work with
theLongRunningTask = New DelegateSub(AddressOf DoTheTimeConsumingTask)
'(2) Set Dispatcher priority as required
priority = System.Windows.Threading.DispatcherPriority.Background
'(3) Add the job to the FlowDocument's Dispatcher's tasks
theDocument.Dispatcher.BeginInvoke(theLongRunningTask, priority)
End Sub
''' <summary>
''' Sub whose logic accesses, but does not change, the UI object
''' </summary>
Private Sub DoTheTimeConsumingTask()
'For example......
For Each bl As Block In theDocument.Blocks
'......do something
Next
End Sub
虽然这似乎工作,因为我看到它的问题是,除了触发与BackgroundWorker的任务,几乎所有的长期运行的任务由UI对象的调度处理。所以BackgroundWorker实际上并没有做任何工作。这是我关心的部分;我看不到我如何得到什么,如果分派器捆绑起来做所有的工作
选项2
因此,它似乎更符合逻辑,我认为我会更好“这扭曲“并将Dispatcher的委托设置为指向实例化并启动BackGroundWorker的子(我认为Dispatcher线程将拥有BackgroundWorker的线程),并执行BackgroundWorker的DoWork事件中的所有工作。这种“感觉”是正确的...。
所以我想这一点,而不是:
WithEvents worker As BackgroundWorker
Private Delegate Sub DelegateSub()
Private theDocument As FlowDocument
''' <summary>
''' Triggers the background task. Can call from anywhere in main code blocks
''' </summary>
Private Sub StartTheBackgroundTask()
Dim priority As System.Windows.Threading.DispatcherPriority
Dim theTask As DelegateSub
'(1) Define a delegate for the Dispatcher to work with
theTask = New DelegateSub(AddressOf RunWorker)
'(2) Set Dispatcher priority as required
priority = System.Windows.Threading.DispatcherPriority.Normal
'(3) Add the job to the Dispatcher's tasks
theDocument.Dispatcher.BeginInvoke(theTask, priority)
End Sub
''' <summary>
''' Creates and starts a new BackGroundWorker object
''' </summary>
Private Sub RunWorker()
Worker = New BackgroundWorker
Worker.RunWorkerAsync()
End Sub
''' <summary>
''' Does the long task in the DoWork event
''' </summary>
Private Sub HandleWorkerDoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
DoTheTimeConsumingTask()
End Sub
''' <summary>
''' Sub whose logic accesses, but does not change, the UI object
''' </summary>
Private Sub DoTheTimeConsumingTask()
'For example......
For Each bl As Block In theDocument.Blocks
'......do something
Next
End Sub
对我来说,所有的似乎更符合逻辑。我推测Dispatcher将拥有BackgroundWorker,而BackgroundWorker将继续完成所有的长时间工作,并且所有事情都将在UI线程上进行。那么... ...对于逻辑思考来说太多了......(通常对于WPF来说是致命的!)......它不会。它与通常的“不同线程”错误崩溃。所以,第二个想法似乎是一个更加优雅的解决方案,原来是一个失败者!
我的问题则是:
- 是我的“解决方案”的解决方案,或不?
- 我哪里错了?
- 怎样才能改善“解决方案”,使调度员不被长时间的工作束缚......这正是我试图避免的情况?
还有一个问题。请注意,我必须使用FlowDocument的调度程序来完成这项工作。如果我使用System.Windows.Threading.Dispatcher.CurrentDispatcher来代替,那么委托子(DoTheTimeConsumingTask)不会被调用 - 所有意图和目的都不会发生。有人可以解释为什么不,请吗?
我还没有来找你作为第一停靠港。我已经尝试了几十种选择,并且还没有发现任何感觉完全正确的东西(除了我的第二个选项,它不起作用),所以我请求一些指导。
无法发表评论;抱歉 – SophieT 2011-05-23 16:08:24
我试图使用Async = True访问FlowDocument,并且遇到了类似的问题。你从DispatchObject派生出来的解释清楚了事情。 +1 – Paparazzi 2011-09-19 00:56:21