Damo
Damo

Reputation: 2070

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. Essentially, I'm writing a twitter application which regularly polls twitter for updates. 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. As a learner, I'm struggling implement a way of updating the GUI by using events.

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?

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

Upvotes: 1

Views: 8931

Answers (4)

Steve
Steve

Reputation: 216343

I will try these change:
In your UpdateTimeLine add

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

In startTimelineUpdater_DoWork remove these lines

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

Upvotes: 0

aKzenT
aKzenT

Reputation: 7915

You can use the Dispatcher 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.

Upvotes: 3

paparazzo
paparazzo

Reputation: 45106

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.

If you want to get intermediate results you can use the progress.

Upvotes: 0

shriek
shriek

Reputation: 5197

You can use the Dispatcher to update your GUI. Check this blog post for a rather good example on how to do it.

Upvotes: 1

Related Questions