У меня есть небольшая проблема с RTB и генерацией документов в отношении потоков.
Когда в RTB возникает событие TextChanged, создается новая thead, и генерация документа выгружается в это. Это может занять пару секунд с блокировкой вызовов, поэтому он действительно должен быть в другом потоке, чтобы пользовательский интерфейс реагировал.
Проблема, с которой я столкнулся, является исключением, когда я пытаюсь добавить вновь сгенерированный документ в свойство Document
RTB. ( Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им.) Это не из-за того, что вы забыли использовать Dispatcher.Invoke
, поскольку именно там генерируется исключение, а потому, что я создаю FlowDocument / Paragraph / Запускать экземпляры в потоке, отличном от потока пользовательского интерфейса (я думаю ??).
Есть ли способ добиться того, что я здесь ищу?
Обновление
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
Обновление № 2 - решение
(сортов)
Итак, как отметил @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;
}