BackgroundWorker и WPF - PullRequest
       5

BackgroundWorker и WPF

3 голосов
/ 31 июля 2011

Я сделал FlowDocument, объект WPF, из DoWork System.ComponentMode.BackgroundWorker, но не могу получить к нему доступ в потоке пользовательского интерфейса WPF.

using System;
using System.Windows;
using System.Windows.Documents;
using System.ComponentModel;
namespace WpfApplication1
{
    public partial class MainWindow : Window
    {

        BackgroundWorker bw = new BackgroundWorker();

        public MainWindow()
        {
            InitializeComponent();

            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            bw.RunWorkerAsync();
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {

            FlowDocument myFlowDocument = new FlowDocument();
            Paragraph myParagraph = new Paragraph();
            myParagraph.Inlines.Add(new Bold(new Run("Some bold text in the paragraph.")));
            myFlowDocument.Blocks.Add(myParagraph);

            e.Result = myFlowDocument;

        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //runtime error occured here.
            fviewer.Document = (FlowDocument)e.Result;
        }

    }
}

Я слышал, когда я получаю доступ к объекту WPF в другом потоке, мне нужно использовать dispatcher (). но RunWorkerCompleted () не является другим потоком пользовательского интерфейса, поэтому я запутался. как я могу получить доступ к myFlowDocument?

Ответы [ 3 ]

2 голосов
/ 31 июля 2011

Проблема в том, что FlowDocument создается в потоке, отличном от потока пользовательского интерфейса.

Вам нужно будет создать потоковый документ в основном потоке пользовательского интерфейса. И тогда в фоновом режиме вам нужно будет использовать потоковые документы Dispatcher.Invoke для установки свойств и создания элементов. В вашем простом примере нет реального преимущества использования фонового работника. Рабочий должен использоваться для обработки ваших длительных процессов.

Единственным другим способом может быть создание документа в фоновом режиме, его сериализация в потоке памяти, а затем десериализация после возврата в поток пользовательского интерфейса.

0 голосов
/ 31 июля 2011

Я сделал «FlowDocument», объект WPF, из DoWork из System.ComponentMode.BackgroundWorker

Не делайте этого.Объекты пользовательского интерфейса должны быть созданы и обновлены из потока пользовательского интерфейса.

0 голосов
/ 31 июля 2011

Как правильно указывает Боб Вейл; Общее правило - никогда не создавать объекты пользовательского интерфейса в другом потоке. При создании объектов презентации; Вы должны сделать это в потоке пользовательского интерфейса. Фоновая задача должна возвращать простые данные. Я бы изменил DoWork, чтобы он выглядел так:

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        //Assume some kind of "work" is being done here.
        e.Result = "Some bold text in the paragraph";
    }

Тогда вы можете установить содержимое документа с помощью Диспетчер :

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Action<string> action = r => 
        {
            FlowDocument myFlowDocument = new FlowDocument();
            Paragraph myParagraph = new Paragraph();
            myParagraph.Inlines.Add(new Bold(new Run(r)));
            myFlowDocument.Blocks.Add(myParagraph);
            fviewer.Document = myFlowDocument;
        };
        Dispatcher.Invoke(action, (string)e.Result);
    }

В этом случае Диспетчер позволяет вам планировать работу (в данном случае делегата) для потока, которому принадлежит пользовательский интерфейс.

...