How to wait till a task is fully completed? - c#

I have a image processing application in which I have 2 modes. Manual inspection and Automatic inspection using a PLC command.
Manual inspection works fine, the user clicks a button to grab an image, and then clicks another button to process the image and send results to the PLC.
But in automatic inspection mode, im getting incorrect inspection result(same product/image inspection in manual mode gets correct result). I suspect that after grabbing image the system is not getting enough time to read the full image before the inspection starts, so I added a thread.sleep(500), But that didnt make any difference. So I tried the async await.task.delay(500) method, same result.
Is there any other way to fix it?
Code:
private async void timer3_Tick(object sender, EventArgs e)
{
btncheckm1_Click(null, null);
var newSignal = textBox8.Text.Contains("+1");
var isRisingEdge = newSignal && (_oldSignal == false);
_oldSignal = newSignal;
if (isRisingEdge)
{
lblmessages.Text = "";
totalsheetcount++;
btngrabimage_Click(null, null);
// Thread.Sleep(300);
await Task.Delay(1000);
processimage();
}
}
btngrabimage() has the following code:
try
{
camimage = null;
cam1.BeginAcquisition();
// Retrieve an image
IManagedImage rawImage = cam1.GetNextImage();
IManagedImage convertedImage = rawImage.Convert(PixelFormatEnums.Mono8);
imagetoinspect = convertedImage.bitmap;
rawImage.Release();
cam1.EndAcquisition();
//cam1.DeInit();
distort();
}
catch (Exception ee)
{
}

I also would say that wrapping the grabbing of an image inside a task and awaiting that result is the way to go. The image class represents your return type as the image. Dont mind the function names though. Task.Run and Task.Factory.StartNew are essentially the same thing, just wanted to show you have different options for creating your task
public class ImageRetriever
{
public void ProcessImage()
{
//if you would like to get rid of the async
//reminder that calling .Result is blocking for the current thread.
//this means the thread will stop working untill the result is returned
//could be an issue if this is called on UI thead
var imageTask = GetImage();
Image image = imageTask.Result;
}
public async Task ProcessImageAsync()
{
//if you want to keep the async-nonblocking
Image image = await GetImage();
}
private Task<Image> GetImage()
{
//this is how your create your task
Task<Image> imageTask;
imageTask = Task.Run(() =>
{
return new Image();
});
// or
imageTask = Task.Factory.StartNew(() =>
{
return new Image();
});
return imageTask;
}
}
public class Image
{
}

Related

Dynamically swapping out or toggling visibility of controls

I have a TreeView in a form, that is dock-filled to a groupbox. The problem to solve is, that there is an operation that is run on a Task, which loads data from a server application. When this is running, there should be a progress indicator displayed in the location of the TreeView. That is, it should be shown instead of the TreeView, and take its place fully. The following is what the code for this looks like:
private async void preload_data(object sender, System.EventArgs args)
{
try
{
// the treeView should be disabled/invisible at this point
// make the CircularProgressBar enabled/visible
// get the information from the server
await Configuration.network.fetch_stuff();
}
catch (Exception ex)
{
// something bad happened
}
finally
{
// whatever happened, the treeView should be back
}
}
The CircularProgressBar (a third-party control) should appear as in the code above, and should replace the TreeView. It should fill the exact same space as the TreeView would, which is dock-filled. Below is a screenshot of this:
This form and all its controls have been designed in the designer, and I don't want to do it there, I want to do it programmatically. What is the best way to go about this? I have looked at examples of Controls.Remove() and Controls.Add(), but it's not clear if that fits this purpose.
It is quite common to change the visual output while actions are running, like you do. Think of disabling buttons, to discourage operators to press the button again, or show something visually, to inform operators about the progress.
For simplicity, without the try-catch
private async Task PreloadDataAsync()
{
this.ShowFetchingData(true);
// start fetching data, do not await:
var taskFetchData = Configuration.network.fetch_stuff();
// while taskFetchData not completed, await some time
TimeSpan updateTime = TimeSpan.FromSeconds(0.250);
int progressCounter = 0;
while (!taskFetchData.IsCompleted)
{
this.ShowProgress(progressCounter);
var taskWait = Task.Delay(updateTime);
await Task.WhenAny(new Task[] {taskFetchData, taskWait};
// either taskFetchData.IsCompleted, or Delay time waited
++progressCounter;
}
this.ShowFetchingData(false);
}
private void ShowFetchindData(bool show)
{
// disable/enable certain buttons, menu items, show progressbar?
this.ButtonFetchData.Enabled = !show;
this.MenuFetchData.Enabled = !show;
this.ProgressBarFetchData.Visible = show;
}
private bool IsFetchingData => this.ProgressBarFetchData.Visible;
private void ShowProgress(int progress)
{
this.ProgressBarFetchData.Position = progress;
}
For simplicity, I've left out checks for the position in the progress bar, but you get the gist.
Usage:
private async void OnButtonFetchData(object sender, EventArgs e)
{
await this.PreloadDataAsync();
}
Room for improvement
The problem with this is that there is no timeout at all: if FetchStuff does not complete, you are in an endless wait. The method that microsoft proposes is the use of a CancellationToken. Almost every async method has an overload with a CancellationToken. Consider creating one yourself:
// existing method:
private async Task<MyData> fetch_Stuff()
{
await this.fetch_stuff(CancellationToken.None);
}
// added method with CancellationToken
private async Task<MyData> fetch_Stuff(CancellationToken token)
{
// Call async function overloads with the token,
// Regularly check if cancellation requested
while (!token.IsCancellationRequested)
{
... // fetch some more data, without waiting too long
}
}
Instead of IsCancellationRequested, consider to throw an exception: ThrowIfCancellationRequested.
Usage:
private async Task PreloadDataAsync()
{
// preloading should be finished within 30 seconds
// let the cancellationTokenSource request cancel after 30 seconds
TimeSpan maxPreloadTime = TimeSpan.FromSeconds(30);
using (var cancellationTokenSource = new CancellationTokenSource(maxPreloadTime))
{
await PreloadDataAsync(cancellationTokenSource.Token);
}
}
The overload with CancellationToken:
private async Task PreloadDataAsync(CancellationToken token)
{
this.ShowFetchingData(true);
// execute code similar to above, use overloads that accept token:
try
{
var taskFetchData = Configuration.network.fetch_stuff(token);
TimeSpan updateTime = TimeSpan.FromSeconds(0.250);
int progressCounter = 0;
while (!taskFetchData.IsCompleted)
{
token.ThrowIfCancellationRequested();
this.ShowProgress(progressCounter);
var taskWait = Task.Delay(updateTime, token);
await Task.WhenAny(new Task[] {taskFetchData, taskWait};
// either taskFetchData.IsCompleted, or Delay time waited
++progressCounter;
}
}
catch (TaskCancelledException exc)
{
this.ReportPreloadTimeout();
}
finally
{
this.ShowFetchingData(false);
}
}
Or if you want a button that cancels the task:
private CancellationTokenSource cancellationTokenSource = null;
private book IsPreloading => this.CancellationTokenSource != null;
private async Task StartStopPreload()
{
if (!this.IsPreloading)
StartPreload();
else
CancelPreload();
}
private async Task StartPreload()
{
// preload not started yet; start it without timeout;
try
{
this.cancellationTokenSource = new CancellationTokenSource();
await PreloadDataAsync(this.cancellationTokenSource.Token);
}
catch (TaskCancelledException exc)
{
this.ReportPreloadCancelled();
}
finally
{
this.cancellationTokenSource.Dispose();
this.cancellationTokenSource = null;
}
}
}
The method where operators can stop preloading:
private async void StopPreload()
{
this.cancellationTokenSource.Cancel();
// the method that created this source will Dispose it and assign null
}
All you have to do is create buttons / menu items to start / stop preloading
Solved using Visible properties of controls.

MapIcon creation in Timer callback

I'm creating a small universal windows application. I'd like to use MapControl to present some data downloaded from the Internet. This data refreshes every minute and I want to update MapIcons positions everytime that it happens.
So... After loading a map, I create a Timer that runs every 60 seconds and downloads the data using HttpWebRequest, then parses received JSON and then updates the positions of MapIcons displayed in MapControl.
Everything should work fine, however when I call new MapIcon() in Timer callback I have an exception:
An exception of type 'System.Exception' occurred in newproject.exe but was not handled in user code
Additional information: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
My Timer callback code is:
private async void OnTimerTick(Object stateInfo)
{
var TramDataList = await Loader.LoadData();
updateMarkers(TramDataList);
}
private void updateMarkers(List<TramData> tramList)
{
lock (TramMarkerDict)
{
foreach (var tramData in tramList)
{
if (!TramDataDict.ContainsKey(tramData.Id))
{
TramDataDict.Remove(tramData.Id);
TramMarkerDict.Remove(tramData.Id);
}
}
foreach (var tramData in tramList)
{
TramData tmp = null;
var exists = TramDataDict.TryGetValue(tramData.Id, out tmp);
if (exists)
tmp.update(tramData);
else
TramDataDict.Add(tramData.Id, tramData);
}
foreach (var tramData in TramDataDict.Values)
{
MapIcon mapIcon = null;
var geopoint = new Windows.Devices.Geolocation.Geopoint(
new Windows.Devices.Geolocation.BasicGeoposition { Latitude = tramData.Lat, Longitude = tramData.Lng });
var exists = TramMarkerDict.TryGetValue(tramData.Id, out mapIcon);
if (exists)
mapIcon.Location = geopoint;
else
{
mapIcon = new MapIcon { Location = geopoint, Title = tramData.FirstLine, NormalizedAnchorPoint = new Point(0.5, 1) };
TramMarkerDict.Add(tramData.Id, mapIcon);
}
}
}
}
Please try using a Dispatcher. You need to add MapIcon objects on the UI Thread.
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// Your Code
});
}
Although Jean-Sébastien Dupuy's answer is technically correct, another option is to use HttpClient instead of HttpWebRequest and use the await keyword to ensure everything automatically runs on the correct thread. (Also make sure you're using a DispatcherTimer and not some other kind of timer).

Restart WPF Application from non-UI thread

In my WPF app I need to run a quick routine on startup that checks for a new available version. If the version is available, we do the update and then would like to immediately restart the app. Since this is run before the main window appears to the user, it simply appears as though the app took a split second longer to start up.
We're using Squirrel.Windows for our updater. I've made the class below to handle checking for/applying updates.
public class UpdateVersion
{
private readonly UpdateManager _updateManager;
public Action<int> Progress;
public event Action Restart;
public UpdateVersion(string squirrelUrl)
{
_updateManager = new UpdateManager(squirrelUrl);
}
public async Task UpdateVersions()
{
using (_updateManager)
{
UpdateInfo updateInfo = await _updateManager.CheckForUpdate(progress:Progress);
if (updateInfo.CurrentlyInstalledVersion == null)
{
if (updateInfo.FutureReleaseEntry != null)
{
await _updateManager.UpdateApp(Progress);
// Job crashes here
Restart?.Invoke();
}
}
else if (updateInfo.CurrentlyInstalledVersion.Version < updateInfo.FutureReleaseEntry.Version)
{
await _updateManager.UpdateApp(Progress);
// Job crashes here
Restart?.Invoke();
}
}
}
}
Unfortunately Squirrel has made their update process async only, which means the CheckForUpdate and UpdateApp method must use await, making the entire update method asynchronous. I assign the asnyc call to a Task, then simply .Wait() for the update to finish.
The problem comes when I try to restart my app. Based on what I've read, I need to use Dispatcher.Invoke to call the restart due to the fact I am on a non-UI thread when performing the update. However, despite the code below, I still get the same error message:
The Calling thread cannot access this object because a different thread owns it
Any idea how to correctly implement Dispatcher.Invoke in order to restart the app?
// Instantiate new UpdateVersion object passing in the URL
UpdateVersion updateVersion = new UpdateVersion(System.Configuration.ConfigurationManager.AppSettings.Get("SquirrelDirectory"));
// Assign Dispatch.Invoke as Restart action delegate
updateVersion.Restart += () =>
{
Dispatcher.Invoke(() =>
{
Process.Start(ResourceAssembly.Location);
Current.Shutdown();
});
};
// This is here for debugging purposes so I know the update is occurring
updateVersion.Progress += (count) =>
{
Debug.WriteLine($"Progress.. {count}");
};
var task = Task.Run(async () => { await updateVersion.UpdateVersions(); });
task.Wait();
EDIT
Below is a screen shot of the Target attribute of the Restart action. The debugger was paused at the Restar?.Invoke line from above.
Instead of trying to convert asynchronous programming to the old event based pattern, just use it properly. You don't need events to detect when an asynchronous operation finished, nor do you need Invoke to move back to the UI thread. await takes care of both.
You could write code as simple as this:
static readonly SemanticVersion ZeroVersion = new SemanticVersion(0, 0, 0, 0);
private async void Application_Startup(object sender, StartupEventArgs e)
{
await CheckForUpdatesAsync();
}
private async Task CheckForUpdatesAsync()
{
string squirrelUrl = "...";
var updateProgress = new Progress<int>();
IProgress<int> progress = updateProgress;
//Create a splash screen that binds to progress and show it
var splash = new UpdateSplash(updateProgress);
splash.Show();
using (var updateManager = new UpdateManager(squirrelUrl))
{
//IProgress<int>.Report matches Action<i>
var info = await updateManager.CheckForUpdate(progress: progress.Report);
//Get the current and future versions.
//If missing, replace them with version Zero
var currentVersion = info.CurrentlyInstalledVersion?.Version ?? ZeroVersion;
var futureVersion = info.FutureReleaseEntry?.Version ?? ZeroVersion;
//Is there a newer version?
if (currentVersion < futureVersion)
{
await updateManager.UpdateApp(progress.Report);
Restart();
}
}
splash.Hide();
}
private void Restart()
{
Process.Start(ResourceAssembly.Location);
Current.Shutdown();
}
This is just enough code to extract to a separate class:
private async void Application_Startup(object sender, StartupEventArgs e)
{
var updater = new Updater();
await updater.CheckForUpdatesAsync(...);
}
// ...
class Updater
{
static readonly SemanticVersion ZeroVersion = new SemanticVersion(0, 0, 0, 0);
public async Task CheckForUpdatesAsync(string squirrelUrl)
{
var updateProgress = new Progress<int>();
IProgress<int> progress = updateProgress;
//Create a splash screen that binds to progress and show it
var splash = new UpdateSplash(updateProgress);
splash.Show();
using (var updateManager = new UpdateManager(squirrelUrl))
{
var updateInfo = await updateManager.CheckForUpdate(progress: progress.Report);
//Get the current and future versions. If missing, replace them with version Zero
var currentVersion = updateInfo.CurrentlyInstalledVersion?.Version ?? ZeroVersion;
var futureVersion = updateInfo.FutureReleaseEntry?.Version ?? ZeroVersion;
//Is there a newer version?
if (currentVersion < futureVersion)
{
await updateManager.UpdateApp(progress.Report);
Restart();
}
}
splash.Hide();
}
private void Restart()
{
Process.Start(Application.ResourceAssembly.Location);
Application.Current.Shutdown();
}
}
So the actual exception is somewhere in the Restart handler is trying to access the MainWindow get property from another thread based on the stack trace. This is a complete guess, but I would store the original Dispatcher in the OnStartup method and use the stored Dispatcher in the Restart event handler.
Why you are not using SplashScreen ? This SplashScreen would check for new versions, and either download updates, or start the old application.
A lovely tutorial to get you started : EASILY CREATE A WPF SPLASH SCREEN WITH STATUS UPDATES VIA MVVM

WinRT - UI virtualization loading images async blocking UI Thread

I'm having problems with my image loading blocking the UI thread so my gridview is not responsive in my windows store app.
What I'm trying to do is for the images in gridview to have a binding to image property in my view model. The value of image property is set by an async method. When app starts it loads all objects, but not the actual image data. The image data is loaded when the UI virtualization kicks in and requestes the image data via the image property bound to the image control in xaml.
All this is done in an observablecollection.
Here is some code:
private ImageSource _image = null;
private String _imagePath = null;
public ImageSource Image
{
get
{
SetImageFromStorageFile().ContinueWith(OnAsyncFail, TaskContinuationOptions.OnlyOnFaulted);
return this._image;
}
}
private async Task SetImageFromStorageFile()
{
this.IsLoading = true;
if (this._image == null && this._imagePath != null)
{
this._image = await BitmapLoader.GetPreviewImageFromStorageFile(this.StorageFile); //getting the actual data here
this.OnPropertyChanged("Image");
}
this.IsLoading = false;
}
This is all working fine except that the UI becomes unresponsive when accessing the image data.
As you can see I'm calling an async method from a property, I'm just reusing the code that I call from other places. When called from other places I can use await and the UI is responsive. The problem is that when using the gridviews UI virtualization I don't know how to run this async method without blocking the UI since properties are not possible to run async (as far as I know).
So I just want the gridview to run this property (or method) async instead of sync, but don't know how to do it.
Please help :)
private ImageSource _image = null;
private String _imagePath = null;
public ImageSource Image
{
get
{
if (_image != null)
return _image;
if (_imagePath != null && !IsLoading)
SetImageFromStorageFile();
return null;
}
}
private async void SetImageFromStorageFile()
{
if (this.IsLoading || this._image != null || this._imagePath == null)
return;
this.IsLoading = true;
try
{
this._image = await BitmapLoader.GetPreviewImageFromStorageFile(this.StorageFile); //getting the actual data here
this.IsLoading = false;
this.OnPropertyChanged("Image");
}
catch
{
OnAsyncFail();
}
}
Whatever strategy you choose, you need to return something first and fill it later. This is a sample which has been tested in a vanilla WinRT page; you can duplicate it by dropping it onto a page with an Image named image and a TextBlock named status. This can go in OnNavigatedTo, or another appropriate place.
BitmapImage imgsrc = new BitmapImage();
Task.Run(async () =>
{
await Task.Delay(10000);
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
new Windows.UI.Core.DispatchedHandler(() =>
{
imgsrc.UriSource = new Uri("http://www.gratuit-en-ligne.com/telecharger-gratuit-en-ligne/telecharger-image-wallpaper-gratuit/image-wallpaper-animaux/img/images/image-wallpaper-animaux-autruche.jpg");
}));
});
image.Source = imgsrc;
status.Text = "Done";
The thing I am "returning" is a BitmapImage, which is a subclass of ImageSource, so it's close to what you will want to use. The Task.Delay() is just to introduce obvious lag between startup and image population, so that you can see that the status text is set well before the image is loaded.
To make this work with your sample, you will need to create (or access) an ImageSource in your property and return it immediately, without waiting for it to be filled. Then you start off a background task that assigns the actual source data.
The actual chain of causation could be different than what I show here. You could, for instance, access the ImageSources from a pre-created collection of them. This would allow you to start loading the images before the property is ever called. But it sounds like this will be a start to get you moving in the right direction.

redraw image during excecution WPF

I have a smal application that should set a image to red or green depending on some tests that are made. The test can take a few second, and each one has a custom control with an image connected to it. When I click start I would like for the first test to be done, show the result by changing the image on that one, and then move on. But as it is now, all tests are made (maybe 10 seconds), then ALL the lights are changing at the same time. How can I force the custom control to update the image during the excecution?
private void start_Click(object sender, RoutedEventArgs e)
{
foreach (TestObject tObj in tObjList)
{
bool testResult = tObj.makeTest();
foreach (TestShower ts in m_TSList)
{
if (tObj == ts.gettObj())
{
if (testResult == true)
ts.setLightOn();
else
ts.setLightOff();
ts.UpdateLayout();
break;
}
}
}
}
public void setLightOn()
{
string strUri2 = String.Format(#"pack://application:,,,/;component/Images/Signal_On.png");
BitmapImage img = new BitmapImage(new Uri(strUri2));
iStatus.Source = null;
iStatus.Source = img;
}
public void setLightOff()
{
string strUri2 = String.Format(#"pack://application:,,,/;component/Images/Signal_Off.png");
BitmapImage img = new BitmapImage(new Uri(strUri2));
iStatus.Source = null;
iStatus.Source = img;
}
you should read into Async and await and perform each test at the same time and await the results (obviously this assumes your tests are not interdependant)
and some form of implementation of
Task.Factory.StartNew(() => {
var result = ts.makeTest();
setLight1(result);
})
Although without knowing more it would seem as though you could perform this using databinding to a ViewModel that implements INotifyPropertyChanged on a List of Test Objects.
but not performing the tests asynchronously is the main cause of your issue
i know external links are not really preferred in SO but here is a tutorial
http://www.youtube.com/watch?v=ZyFL3hjHADs
Run the tests in the background and then use Dispatcher to update UI thread:
For WPF & Net 4.5. you can use TPL
private void start_Click(object sender, RoutedEventArgs e)
{
Task.Run(()=>{
foreach (TestObject tObj in tObjList)
{
bool testResult = tObj.makeTest();
Dispatcher.Invoke(()=>{
foreach (TestShower ts in m_TSList)
{
if (tObj == ts.gettObj())
{
if (testResult == true)
ts.setLightOn();
else
ts.setLightOff();
ts.UpdateLayout();
break;
}
}});
}
}
});
}

Categories