WPF waiting for the UI to finish - wpf

I have a code that needs to refresh the UI then wait for it to finish (refreshing may involve animations) and then keep going. Is there a way to call the Application.Current.Dispatcher.Invoke(new Action (()=> { PerformUpdateWithAnimations(); } in a syncrhonous way?
This is the overall look:
List<thingsThatMove> myThings = new List<ThingsThatMove>();
//normal code interacting with the data
// let's name this part of code A
foreach (thing t in myThings)
{
thing.currentPosition = SomePoint;
if(thing.wasRejectedBySystem) thing.needsToMove = true;
}
//As a result of A we have some impact in the UI
//That may need some animations (let's call this bloc B)
Application.Current.Dispatcher.Invoke(new Action(() => {
foreach(thing in myThings)
if(thing.needsToMove)
createNewAnimation(thing);
}));
//Here is some final code that needs the final position of some
//of the elements, so it cannot be executed until the B part has
// been finished. Let's call this bloc C
updateInternalValues(myThings);
cleanUp();
I tried encapsulating B into a BackgroundWoker. Setting the B bloc as the DoWork and listening to the completed but it doent work since the B blok "completes" after the Application.Current.Dispatcher is called, not after the dispatcher itself finishes everything
How can I make C wait until all the animations in B are finished ?

You can use async/await to call asynchrnously and continue after it has been executed..
private async void RefreshCode()
{
List<thingsThatMove> myThings = new List<ThingsThatMove>();
//normal code interacting with the data
// let's name this part of code A
foreach (thing t in myThings)
{
thing.currentPosition = SomePoint;
if(thing.wasRejectedBySystem) thing.needsToMove = true;
}
//As a result of A we have some impact in the UI
//That may need some animations (let's call this bloc B)
await Application.Current.Dispatcher.InvokeAsync(new Action(() => {
foreach(thing in myThings)
if(thing.needsToMove)
createNewAnimation(thing);
}));
//Here is some final code that needs the final position of some
//of the elements, so it cannot be executed until the B part has
// been finished. Let's call this bloc C
updateInternalValues(myThings);
cleanUp();
}

Related

MSTest where constructor leads to asynchronous method

I have a viewmodel whose constructor leads to some asynchronous calls and I'm having trouble testing their result.
public ExamAcquireImageViewModel(ICore coreInstance, ExamManager examManager, Action cancelHandler) : base(examManager)
{
TemplateVm.OnSelectionChanged += StartAcquiringImages;
// BECAUSE OF PREVIOUS LINE, THIS CALLS StartAcquiringImages()
SelectedLocationInTemplate = SelectedLocationInTemplate ?? FindNextLowest();
}
private void StartAcquiringImages(LocationViewModel nextLocation = null)
{
new Thread(() =>
{
// expensive operation
_recon = _coreInstance.AcquireImageSet(Exam, SelectedLocationInTemplate.LocationModel);
int width = 1000;
int height = 1000;
// (less) expensive operation
AcquiredImage = _recon?.RenderImageAndGetCurrentFrame().ToWriteableBitmap(width, height);
SelectedLocationInTemplate = GetNextLocation();
}).Start();
}
The constructor assigns the OnSelectionChanged and then changes the selection, setting off the image acquisition process. I want to test that AcquireImages has been assigned to.
public void TestAcquisition()
{
ExamAcquireImageViewModel acqVm = new ExamAcquireImageViewModel(mockCore.Object, examManager, () => { });
Assert.IsNotNull(acqVm.AcquiredImage);
}
I have all my Moqs set up correctly. However because of the threaded/asynchronous operations, the test fails because the assertion runs before any AcquiredImage gets set (indeed, I imagine, before anything in the new Thread gets run).
I've tried ExamAcquireImageViewModel acqVm = await new ExamAcquireImageViewModel(mockCore.Object, examManager, () => { }); but that doesn't compile (no GetAwaiter etc).
How do I wait for this thread in my tests?
I'll also want to test that the SelectedLocationInTemplate "increments" automatically and each next image gets acquired (see last line in the Thread). I don't know where I'd intercept or "peek into" the whole process to see that happening.
For anyone who has a similar problem, I will answer my own question.
It's very very very simple. Thread.Sleep.
[TestMethod]
public void TestAcquisitionSucess()
{
ExamAcquireImageViewModel acqVm = GetAcqVm();
Thread.Sleep(30);
Assert.IsNotNull(acqVm.AcquiredImage);
}

How to check if multiple background workers completed and to update the UI thread?

I am creating a WPF application to collect logs. I am using different Backgroundworker to execute some scripts. Worker1 for script1, Worker2 for script2 and so on. When Backgroundworker completes RunworkerCompleted method get executed.
So, how can I wait for all the workers to complete? Once all these workers are complete, I need to update the UI thread.
You can try using Tasks.
Task t1 = Task.Run(() =>
{
// Do something
}
);
Task t2 = Task.Run(() =>
{
// Do something
}
);
Task t3 = Task.Run(() =>
{
// Do something
}
);
await Task.WhenAll(new Task[] { t1, t2, t3 }).ContinueWith((task) =>
{
// Do something when all three tasks have completed...
}
);
Here is a way to wait for all BackgroundWorker objects to get complete. I hope you are using C#:
static void Main(string[] args)
{
int noOfbackgroundWorker = 5;
WaitHandle[] waitHandles = new WaitHandle[noOfbackgroundWorker];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < noOfbackgroundWorker; i++)
{
var bg1 = new BackgroundWorker();
var handle = new EventWaitHandle(false, EventResetMode.ManualReset);
bg1.DoWork += delegate(object sender, DoWorkEventArgs e) { Thread.Sleep(i * 1000); };
bg1.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { handle.Set(); };
waitHandles[i] = handle;
bg1.RunWorkerAsync();
}
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("Done in "+sw.Elapsed.Seconds + " seconds");
Console.ReadKey();
}
Apart from above if there is low no of BackgroundWorker, just set a bool variable for each worker to map each worker complete status and call a common method from all RunworkerCompleted event handler that just has condition if(a && b && c.....) if passed then notify the UI.
As I say in my Task.Run vs BackgroundWorker conclusion:
anything like waiting for two separate background operations to complete before doing something else is much easier with Task.Run. Pretty much any time you have to coordinate background operations, Task.Run code is going to be much simpler!
(this is the conclusion of a series of blog posts comparing Task.Run to BackgroundWorker).
Worker1 for script1, Worker2 for script2 and so on.
You can do this with Task.Run:
Result DoWork(Script script) { ... }
IEnumerable<Script> scripts = ...;
var tasks = scripts.Select(x => Task.Run(() => DoWork(x))).ToList();
So, how can I wait for all the workers to complete? Once all these workers are complete, I need to update the UI thread.
Use await and Task.WhenAll:
var results = await Task.WhenAll(tasks);
... // Update UI with results

Awaiting IEnumerable<Task<T>> individually C#

In short, I have a Task enumerable, and I would like to run each Task within the array in an await fashion. Each Task will perform a slow network operation and from my end I simply need to update the WinForm UI once the task is finished.
Below is the code I'm currently using, however I think this is more of a hack than an actual solution:
private void btnCheckCredentials_Click(object sender, EventArgs e)
{
// GetNetCredentials() is irrelevant to the question...
List<NetworkCredential> netCredentials = GetNetCredentials();
// This call is not awaited. Displays warning!
netCredentials.ForEach(nc => AwaitTask(ValidateCredentials(nc)));
}
public async Task<bool> ValidateCredentials(NetworkCredential netCredential)
{
// Network-reliant, slow code here...
}
public async Task AwaitTask(Task<bool> task)
{
await task;
// Dumbed-down version of displaying the task results
txtResults.Text += task.Result.ToString();
}
2nd line of btnCheckCredentials_Click() warning is shown:
Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
This actually works the way I wanted to, since I do not want to wait for the operation to complete. Instead I just want to fire away the tasks, and then do something as soon as each one of them finishes.
The Task.WhenAny() or Task.WhenAll() methods do function as I expect, since I would like to know of every task finishing - as soon as it finishes. Task.WaitAll() or Task.WaitAny() are blocking and therefore undesirable as well.
Edit: All tasks should start simultaneously. They may then finish in any order.
Are you looking for Task.WhenAll?
await Task.WhenAll(netCredentials.Select(nc => AwaitTask(ValidateCredentials(nc)));
You can do all the completion processing you need in AwaitTask.
The await task; is a bit awkward. I'd do it like this:
public async Task AwaitTask(netCredential credential)
{
var result = await ValidateCredentails(credential);
// Dumbed-down version of displaying the task results
txtResults.Text += result.ToString();
}
You can do this by using Task.WhenAny marking it as async (async void here is fine since you're inside an event handler):
private async void btnCheckCredentials_Click(object sender, EventArgs e)
{
// GetNetCredentials() is irrelevant to the question...
List<NetworkCredential> netCredentials = GetNetCredentials();
var credentialTasks = netCredentials
.Select(cred => ValidateCredentialsAsync(cred))
.ToList();
while (credentialTasks.Count > 0)
{
var finishedTask = await Task.WhenAny(credentialTasks);
// Do stuff with finished task.
credentialTasks.Remove(finishedTask);
}
}
You can fire and forget each task and add callback when task is completed.
private async void btnCheckCredentials_Click(object sender, EventArgs e)
{
List<NetworkCredential> netCredentials = GetNetCredentials();
foreach (var credential in netCredentials)
{
ValidateCredentails(credential).ContinueWith(x=> ...) {
};
}
}
So instead of labda expression you can create callback method and know exactly when the particular task finished.

Windows Form UI Update issue with Task in C#

We are working on a windows application which caters to an engineering calculation which are essentially very long running. So we are basically trying to keep the calculation module separate and working in a separate worker thread and pass it an Action delegate in method signature which will be invoked to report the calculation progress in the UI. The delegate handler declared in the UI will be updating the UI. We found that while a huge loop is running in the calculation, the UI is not showing the periodic progress and only displaying the final result. If a Thread Sleep for 1 millisecond is introduced in the calculation loop, the UI is getting updated correctly. This is not expected behavior as we are executing the calculation using a separate Task and updating the UI using BeginInvoke calls.
I have created a simple application to demonstrate our approach and code so that it is easier to understand. It is obvious that we are missing something very simple but cannot quite pin it down. Will appreciate any insights.
Thanks for reading.
private void cmdStart_Click(object sender, EventArgs e)
{
txtResultDIsplay.Text = "";
var maxIterations = long.Parse(txtIterationNo.Text.Trim());
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task<double> calculationTask = Task.Factory.StartNew<double>(
() => SumRootN(maxIterations, UpdateProgress));
var handleResultTask = calculationTask.ContinueWith((t) => DisplayResult(t),
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ui);
}
private void DisplayResult(Task<double> calculationTask)
{
txtResultDIsplay.Text = "Final Calculation Result : " + calculationTask.Result.ToString();
}
private void UpdateProgress(string msg)
{
this.BeginInvoke((MethodInvoker)delegate
{
txtResultDIsplay.Text = msg;
});
}
public double SumRootN(long maxIterations, Action<string> progressUpdateDelegate)
{
int root = 20;
double result = 0;
for (long i = 1; i < maxIterations; i++)
{
Thread.Sleep(1);
result += Math.Exp(Math.Log(i) / root);
progressUpdateDelegate(result.ToString("0.00000"));
}
return result;
}
It is possible you are flooding the UI thread with your progress updates. You need to find a way to prevent lots of updates occurring.
We can solve the problem using tasks!
Task progressTask = null;
private void UpdateProgress(string msg)
{
//only schedule work if the task if not running
if(progressTask == null || progressTask.IsCompleted) //updates will end if there is an exception!
{
//Create a task representing the update
progressTask = Task.Factory.FromAsync<object>(BeginInvoke(new Action(() => txtResultDIsplay.Text = msg)), this.EndInvoke)
.ContinueWith(() => System.Threading.Thread.Sleep(100)); //add a sleep on the end
}
}
Note that locking will not do here as you want to skip the update if there is already an update occurring.

How to get Json Array to work inside Asyntask - Android [duplicate]

This question already has an answer here:
How to put Json inside asynctask - Android
(1 answer)
Closed 9 years ago.
I have an Asynctask that uses a Json function in the doInBackground part. The function collects an array of comments and places them into a variable called KEY_COMMENTS. In the onPreExecute it places the comments into a textView using a for loop to select each comment individually. The problem is that its not selecting each comment it will only select one. If I set the loop to go for more than 1 time it will crash the app. Here is my code,
class loadComments extends AsyncTask<JSONObject, String, JSONObject> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
protected JSONObject doInBackground(JSONObject... params) {
//do your work here
JSONObject json2 = CollectComments.collectComments(usernameforcomments, offsetNumber);
return json2;
}
#Override
protected void onPostExecute(JSONObject json2) {
try {
if (json2.getString(KEY_SUCCESS) != null) {
registerErrorMsg.setText("");
String res2 = json2.getString(KEY_SUCCESS);
if(Integer.parseInt(res2) == 1){
JSONArray array = json2.getJSONArray(KEY_COMMENT);
for(int i = 0; i < 2; i++) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
commentBox.setBackgroundResource(R.drawable.comment_box_bg);
layoutParams.setMargins(0, 10, 0, 10);
commentBox.setPadding(0,0,0,10);
commentBox.setOrientation(LinearLayout.VERTICAL);
linear.addView(commentBox, layoutParams);
commentBoxHeader.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
commentBoxHeader.setBackgroundResource(R.drawable.comment_box_bg);
commentBoxHeader.setBackgroundResource(R.drawable.comment_box_header);
commentBox.addView(commentBoxHeader);
commentView.setText(array.getString(i));
LinearLayout.LayoutParams commentViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
commentViewParams.setMargins(20, 10, 20, 20);
commentView.setBackgroundResource(R.drawable.comment_bg);
commentView.setTextColor(getResources().getColor(R.color.black));
commentBox.addView(commentView, commentViewParams);
}
}//end if key is == 1
else{
// Error in registration
registerErrorMsg.setText(json2.getString(KEY_ERROR_MSG));
}//end else
}//end if
} //end try
catch (JSONException e) {
e.printStackTrace();
}//end catch
}
}
doInBackGround : method is used as a Thread !
onPostExecute : acts as a UI Thread !
So try to put your any-long running code in , doInBackGround method !
When an asynchronous task is executed, the task goes through 4 steps:
From the Docs :
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

Resources