У меня небольшая проблема с RTB и генерацией документов в отношении потоков.
Когда событие TextChanged запускается в RTB, создается новая тема, и в нее выгружается генерация документа. Это может занять пару секунд с блокирующими вызовами, так что действительно нужно быть в другом потоке, чтобы пользовательский интерфейс оставался отзывчивым.
Проблема I ' m является исключением, когда я пытаюсь добавить вновь созданный документ к свойству Document
RTB. ( Вызывающий поток не может получить доступ к этому объекту, потому что он принадлежит другому потоку.) Это происходит не из-за того, что вы забыли использовать Dispatcher.Invoke
, поскольку именно здесь генерируется исключение, а потому, что Я создаю экземпляры FlowDocument / Paragraph / Run в потоке, отличном от потока пользовательского интерфейса (я думаю ??).
Есть ли способ достичь того, что я ищу здесь?
private void rtbQuery_TextChanged(object sender, TextChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Requires update; on thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Generating; on thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
DocumentGenerator dgen = new DocumentGenerator();
string queryText = getQueryText();
e.Result = dgen.GenerateDocument(queryText);
}
private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Assigning; on thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
FlowDocument doc = (FlowDocument)e.Result;
txtQuery.Document = doc; // ! The calling thread cannot access this object because a different thread owns it
}
>Requires update; on thread:9
>Generating; on thread:10
>Assigning; on thread:9
(своего рода)
Итак, как заметил @Jon Mitchell, я не могу обновить свой RTB в потоке пользовательского интерфейса с объектом, созданным в другом потоке. Однако есть очень простое решение, которое требует минимального изменения кода, чтобы обойти это, и я ' м размещать его, чтобы избавить будущих людей от хлопот. Вкратце объясняется, что граф объектов создается в другом потоке, а затем преобразуется в XAML. Затем поток пользовательского интерфейса преобразует этот XAML обратно в граф объектов в своем собственном потоке, и все работает нормально.
private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
DocumentGenerator dgen = new DocumentGenerator();
string queryText = getQueryText();
dgen.GenerateDocument(queryText); // start generation
e.Result = dgen; // note, i'm passing the generator, not the document
}
private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
DocumentGenerator dgen = (DocumentGenerator)e.Result;
txtQuery.Document = dgen.GetFlowDocument();
}
В классе DocumentGenerator
public void GenerateDocument(string data)
{
... // build up the document DOM
// return documentDOM; // used to return the generated item here.
documentXAML = System.Windows.Markup.XamlWriter.Save(documentDOM); // serialize the DOM to XAML
}
public FlowDocument GetDocument()
{
object result = System.Windows.Markup.XamlReader.Parse(documentXAML); // build DOM from XAML
return (FlowDocument)result;
}