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";
}
}
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
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.
You can use the Dispatcher to update your 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.
If you want to get intermediate results you can use the progress.