訪問一個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