Reputation: 21
I am trying to implement a "long wait" dialog to show a progress bar in a window during a long operation. I know there are some stock examples of this online. I am trying to understand why mine does not work so I can learn something about threading from it.
What happens when I run this is that the breakpoint at line 1 of process.Begin is never hit. Why is that?
public partial class LongWaitDlg : Window
{
private ILongWaitProcess process;
public LongWaitDlg(ILongWaitProcess process)
{
InitializeComponent();
Progress.Maximum = 1;
Progress.Value = process.IsLiveUpdating() ? 0 : 1;
this.process = process;
Dispatcher.BeginInvoke((Action) (() => this.ManageProgress()));
}
public void ManageProgress()
{
Dispatcher.BeginInvoke((Action)(() => process.Begin()));
while (!Dispatcher.Invoke<bool>(process.IsComplete))
{
double progress = Dispatcher.Invoke<double>(process.GetProgress);
Progress.Value = progress;
Console.WriteLine(progress);
Thread.Sleep(1000);
}
this.Close();
}
}
Upvotes: 1
Views: 443
Reputation: 6615
You need to run your operation in another thread. Dispatcher.BeginInvoke
allows you to continue execution on the primary thread, but it shouldn't be used to start a long-running unit of uninterrupted work because doing that will block all other activities on the primary thread, including other calls to Dispatcher.BeginInvoke
, and responses required to keep your UI up to date.
Annotating your source, this is what is happening:
public void ManageProgress()
{
// This queues up a message to run process.Begin(),
// but will not begin until this function and other callers ahead
// of it have returned control to the Dispatcher
Dispatcher.BeginInvoke((Action)(() => process.Begin()));
// This is waiting on a response from process, but it will get
// stuck in the loop here. Also, using Dispatcher.Invoke<> is suspect here.
// By looping here, we prevent the prior call to BeginInvoke from working.
while (!Dispatcher.Invoke<bool>(process.IsComplete))
{
// ...
}
this.Close();
}
Instead of using Dispatcher.BeginInvoke
to launch your unit of work, consider using any number of alternatives, such as System.Task
(async/wait in .net 4.5), System.Threading.Thread
, or ThreadPool.QueueUserWorkItem
. All of these will allow you to schedule work outside of the primary thread, and you can use Dispatcher.BeginInvoke
from outside (your work item) to schedule updates to your UI, presumably to an updated version of your ManageProcess()
method.
Asynchronous Programming with Async and Await at MSDN
Thread Class (System.Threading) at MSDN
ThreadPool.QueueUserWorkItem at MSDN
Upvotes: 1