As a training exercise, I am creating a counter that runs in a background thread, in a .NET 3.5 WPF app. The idea is that the counter gets incremented and every few seconds the total is output to the screen.
As it is a training exercise, the foreground thread doesn’t really do anything, but imagine that it does!
There is a start and stop button to start and stop the counter.
The problem is that I want the foreground thread to poll the total every few seconds and update it in the text box on the form. The entire app goes ‘Not Responding’ when I try this. Currently I have only got it to update the count a fixed time after it starts it.
I’ll dump all the code in here, so that you get the whole picture:
public partial class Window1 : Window
{
public delegate void FinishIncrementing(int currentCount);
private int reportedCount;
private Thread workThread;
public Window1()
{
InitializeComponent();
}
#region events
private void Window_Loaded(object sender, RoutedEventArgs e)
{
txtCurrentCount.Text = "0";
reportedCount = 0;
InitialiseThread();
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
workThread.Start();
// Do some foreground thread stuff
Thread.Sleep(200); // I want to put this in a loop to report periodically
txtCurrentCount.Text = reportedCount.ToString();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
workThread.Abort();
txtCurrentCount.Text = reportedCount.ToString();
InitialiseThread();
}
#endregion
private void InitialiseThread()
{
WorkObject obj = new WorkObject(ReportIncrement, reportedCount);
workThread = new Thread(obj.StartProcessing);
}
private void ReportIncrement(int currentCount)
{
reportedCount = currentCount;
}
}
public class WorkObject
{
private Window1.FinishIncrementing _callback;
private int _currentCount;
public WorkObject(Window1.FinishIncrementing callback, int count)
{
_callback = callback;
_currentCount = count;
}
public void StartProcessing(object ThreadState)
{
for (int i = 0; i < 100000; i++)
{
_currentCount++;
if (_callback != null)
{
_callback(_currentCount);
Thread.Sleep(100);
}
}
}
}
My question is: how do I get it to report periodically, and why does it fail when I try to put the reporting in a for loop?
Edit: Should have mentioned that my training exercise was to familiarise myself with the old-school method of multithreading, so I cannot use BackgroundWorker!
Every form in a windows application has a message loop that looks something like this:
This applies to all windows applications not just .Net ones. WPF provides a default implementation of WinProc that goes something like this:
As you can see this means that a window can only process one message/event at a time. As you are sleeping in your Button Click event the message loop is being held up and the application stops responding (getting and processing messages).
If you use a DispatcherTimer it asks windows to periodically stick a WM_TIMER (Tick) message in the windows message queue. This allows your application to process other messages while still being able to do something at regular intervals without using another thread.
For more detail see MSDN “About Messages and Message Queues“