简体   繁体   English

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

[英]Update GUI from background worker or event

I want to understand how I can update my GUI with a simple text string on a regular basis.我想了解如何使用简单的文本字符串定期更新我的 GUI。 Essentially, I'm writing a twitter application which regularly polls twitter for updates.本质上,我正在编写一个 twitter 应用程序,它定期轮询 twitter 以获取更新。 I want the contents of the update to be shown in a text block, one by one on a constant loop.我希望更新的内容显示在一个文本块中,一个一个地循环显示。

In order to keep the GUI responsive I need to perform the query in a background worker thread, however updating the GUI from this thread is not possible.为了保持 GUI 响应,我需要在后台工作线程中执行查询,但是无法从该线程更新 GUI。 As a learner, I'm struggling implement a way of updating the GUI by using events.作为一名学习者,我正在努力实现一种通过使用事件来更新 GUI 的方法。

In my code below, I appreciated 'MainWindowGoUpdate' is going to be on the 'wrong thread' but how can I get the GUI thread to listen for the event?在我下面的代码中,我意识到“MainWindowGoUpdate”将出现在“错误的线程”上,但是我怎样才能让 GUI 线程监听事件呢?

A pointer appreciated.一个指针表示赞赏。

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

You can use the Dispatcher class:您可以使用调度员 class:

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

However in your case I would collect the results from the BackgroundWorker in a local variable and then change your label to loop through the results based on a WPF Timer object.但是,在您的情况下,我会在局部变量中收集来自 BackgroundWorker 的结果,然后更改您的 label 以基于 WPF Timer object 循环遍历结果。

You can use the Dispatcher to update your GUI.您可以使用 Dispatcher 来更新您的 GUI。 Check this blog post for a rather good example on how to do it.查看此博客文章以获得有关如何执行此操作的一个很好的示例。

Where you你在哪里

  txtb_timeline.Text = "should not see this";

Is where you get the results.是您获得结果的地方。 Results will be in e.Result And you can pack e.Result with multiple properties.结果将在 e.Result 中,您可以将 e.Result 与多个属性打包在一起。

If you want to get intermediate results you can use the progress.如果你想获得中间结果,你可以使用进度。

I will try these change:我会尝试这些改变:
In your UpdateTimeLine add在您的 UpdateTimeLine 添加

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

In startTimelineUpdater_DoWork remove these lines在 startTimelineUpdater_DoWork 中删除这些行

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

and insert these:并插入这些:

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

finally add the progress event最后添加进度事件

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

Now you can leave only the call to UpdateTimeLine and remove the MainWindowGoUpdate method现在您可以只保留对 UpdateTimeLine 的调用并删除 MainWindowGoUpdate 方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM