Reputation: 461
I have a wpf application where I want to start a loading indicator before a task and end after task done. But the indicator starts after the task executes. What I am trying is as follows.
private void RunAllScriptsChildwdwBtnOK_Click(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync(); // this supposed to start progress bar
_RunAllScripts_Click();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
this.Dispatcher.Invoke(() =>
{
... Start loading indicator
});
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
... End loading indicator
}
But loading indicator starts and ends (as supposed in worker events) only after _RunAllScripts_Click(); method execution is complete. (I found that after unsubscribing from worker_RunWorkerCompleted event, progress bar starts and stays as is because no code to end it).
Also I want to add that, breakpoint hits worker_DoWork method before the execution, but UI updates after execution as I indicated above.
Thanks for all help you will be able to provide.
Upvotes: 0
Views: 583
Reputation: 461
Dear kind people helping me about this subject, thank you all. This works for me, hope it works for all.
BackgroundWorker bwTestAll = new BackgroundWorker() { WorkerReportsProgress = true };
bwTestAll.DoWork += new DoWorkEventHandler(TestAll);
bwTestAll.RunWorkerCompleted += TestAll_RunWorkerCompleted;
//this is where I initialize my loading ring and other stuff and marshall background
//worker to do the main work
Dispatcher.Invoke(new Action(() =>
{
EnableLoading = true;
RunAllScriptsTest.IsEnabled = false;
}), DispatcherPriority.ContextIdle);
bwTestAll.RunWorkerAsync();
//this is my main work
void TestAll(object sender, DoWorkEventArgs e)
{
presenter.RunAllScripts(true);
}
//this is where I do my post-work stuff
private void TestAll_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
/
EnableLoading = false;
RunAllScriptsTest.IsEnabled = true;
DbExecGrid = this.ExecutionResults;
ShowOrHideExecGrid(this.EnableOrDisableGrid);
}), DispatcherPriority.ContextIdle);
}
*Please Notice that Dispatcher with "DispatcherPriority.ContextIdle" works for me.
Upvotes: 0
Reputation: 17392
Using async/await
will work. The await
keyword will allow you to run work without affecting/blocking the UI thread (allowing message pumping to still occur). Once the work has finished, any code after the await
keyword will execute.
Note that I have also wrapped the await
work in an InvokeAsync
call, as it appears that additional work you are doing required UI thread access.
private async void RunAllScriptsChildwdwBtnOK_Click(object sender, RoutedEventArgs e)
{
//TODO ... Start loading indicator
await Task.Run(async ()=>
{
await Application.Current.Dispatcher.InvokeAsync(()=>
{
_RunAllScripts_Click();
});
});
//TODO ... End loading indicator
}
Upvotes: 0
Reputation: 5893
If i was you i would use the async + await keyword for this
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// this is where you would enable your indicator
Button.IsEnabled = false;
await Task.Run(
() =>
{
// this is where you put your work, which should be executed in the background thread.
Thread.Sleep(2000);
});
// this is where you would disable it
Button.IsEnabled = true;
}
Upvotes: 2