从后台工作者或事件更新GUI

时间:2012-04-04 22:08:33

标签: c# wpf multithreading events backgroundworker

我想了解如何定期使用简单的文本字符串更新GUI。 基本上,我正在编写一个Twitter应用程序,定期轮询twitter以获取更新。我希望更新的内容在一个常量循环中逐个显示在文本块中。

为了保持GUI响应,我需要在后台工作线程中执行查询,但是无法从该线程更新GUI。作为一个学习者,我正在努力实现一种通过使用事件来更新GUI的方法。

在我的下面的代码中,我赞赏'MainWindowGoUpdate'将出现在“错误的线程”上但是如何让GUI线程来监听事件呢?

指针赞赏。

public partial class MainWindow : Window
{
  public MainWindow()
  {
    public static event UpdateTimeLineEvent _goUpdate;

    public static string TheTimeLine;
    UpdateTimeLine();
  }

  private void UpdateTimeLine()
  {        
   txtb_timeline.Text = "Updating...";

   BackgroundWorker startTimelineUpdater = new BackgroundWorker();
   startTimelineUpdater.DoWork += new DoWorkEventHandler(startTimelineUpdater_DoWork);
   startTimelineUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(startTimelineUpdater_RunWorkerCompleted);
   startTimelineUpdater.RunWorkerAsync();        
  }

  void startTimelineUpdater_DoWork(object sender, DoWorkEventArgs e)
  {
    while (true)
    {
      Xtweet getSQL = new Xtweet();
      var sqlset = getSQL.CollectLocalTimelineSql();

      int i = 0;
      while (i < 10)
      {
        foreach (var stringse in sqlset)
        {
          StringBuilder sb = new StringBuilder();

          sb.Append(stringse[0] + ": ");
          sb.Append(stringse[1] + " @ ");
          sb.Append(stringse[2]);

          sb.Append("\n");

          TheTimeLine = sb.ToString();

          _goUpdate += new UpdateTimeLineEvent(MainWindowGoUpdate);
          _goUpdate.Invoke();

          Thread.Sleep(10000);
          i++;
        } 
      } 
    }        
  }
  void MainWindowGoUpdate()
  {
    txtb_timeline.Text = TheTimeLine;
  }
  void startTimelineUpdater_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
    txtb_timeline.Text = "should not see this";
  }  
 }

4 个答案:

答案 0 :(得分:2)

您可以使用Dispatcher类:

Dispatcher.BeginInvoke(
    DispatcherPriority.Input, new Action(() => 
    { 
        //update UI
    }));

但是在我的情况下,我会在局部变量中从BackgroundWorker收集结果,然后根据WPF Timer对象更改标签以循环显示结果。

答案 1 :(得分:1)

您可以使用Dispatcher更新GUI。请查看this blog post以获取有关如何操作的相当好的示例。

答案 2 :(得分:0)

你在哪里

  txtb_timeline.Text = "should not see this";

是获得结果的地方。结果将在e.Result中 您可以使用多个属性打包e.Result。

如果您想获得中间结果,可以使用进度。

答案 3 :(得分:0)

我会尝试这些改变:
在UpdateTimeLine中添加

 startTimelineUpdater.WorkerReportsProgress = true;
 startTimelineUpdater.ProgressChanged += new ProgressChangedEventHandler
                                      (startTimelineUpdater_ProgressChanged);

在startTimelineUpdater_DoWork中删除这些行

TheTimeLine = sb.ToString();  
_goUpdate += new UpdateTimeLineEvent(MainWindowGoUpdate);  
_goUpdate.Invoke();  

并插入以下内容:

BackgroundWorker bkgwk = sender as BackgroundWorker;
bkgwk.ReportProgress(0, sb.ToString());

最后添加进度事件

private void startTimelineUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
   txtb_timeline.Text = e.ObjectState.ToString();
}

现在您只能调用UpdateTimeLine并删除MainWindowGoUpdate方法