【问题标题】:BackgroundWorker and WPFBackgroundWorker 和 WPF
【发布时间】:2011-07-31 22:46:42
【问题描述】:

我从 System.ComponentMode.BackgroundWorker 的 DoWork 制作了一个“FlowDocument”,一个 WPF 对象,但我无法在 WPF UI 线程中访问它。

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() 不是 UI 的另一个线程,所以我很困惑。 如何访问 myFlowDocument?

【问题讨论】:

    标签: wpf multithreading backgroundworker


    【解决方案1】:

    问题是因为 FlowDocument 是在与 UI 线程不同的线程中创建的。

    您需要在主 UI 线程上创建流文档。然后在您的后台工作人员中,您将不得不使用流文档 Dispatcher.Invoke 来设置属性并创建项目。在您的简单示例中,使用后台工作人员没有真正的优势。工作人员应该用于处理您的长时间运行的进程。

    唯一的其他方法可能是在后台工作程序中创建文档,将其序列化为内存流,然后在返回 UI 线程后反序列化。

    【讨论】:

      【解决方案2】:

      正如 Bob Vale 正确指出的那样;一般的经验法则是永远不要在另一个线程上创建 UI 对象。当您创建演示对象时;您应该在 UI 线程上执行此操作。后台任务应该返回简单的数据。我会将 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";
          }
      

      然后您可以通过Dispatcher 设置文档内容:

          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);
          }
      

      在这种情况下,Dispatcher 所做的是允许您针对拥有 UI 的线程安排工作(在这种情况下是委托)。

      【讨论】:

      • 但是 fviewer 和流文档是在单独的线程上创建的,所以你不能将它们结合起来。
      • @mjk6026 - 请尝试所做的修改。
      【解决方案3】:

      我从 System.ComponentMode.BackgroundWorker 的 DoWork 制作了一个“FlowDocument”,一个 WPF 对象

      不要那样做。 UI 对象需要从 UI 线程创建和更新。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多