Block code and wait for event handler to fire? - c#

I'm writing an application that uses a 3rd party library to process some data. In a very simplified example, I have a method which runs as a task like this:
private void ProcessListOfItems(List<string> items)
{
while (items.Count > 0)
{
3rdPartyLibObject.Process(items[0]);
items.Remove(0);
}
}
As you can see, the way my code is currently written, I remove each item from the list as soon as the Process() method returns. But it's possible that the processing of an item could fail and I need to know if that happens. Unfortunately, the Process() method does not return a bool value to indicate that the item was successfully processed or not but rather it will fire ProcessingComplete and ProcessingFailed events. I have event handlers hooked up to those events like this:
3rdPartyLibObject.ProcessingComplete += obj_ProcessingSuccess;
3rdPartyLibObject.ProcessingFailed += obj_ProcessingFailed;
private void obj_ProcessingSuccess(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
this.Invoke(new ProcessedHandler(OnProcessed), new object[] { true });
}
private void obj_ProcessingFailed(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
this.Invoke(new ProcessedHandler(OnProcessed), new object[] { false });
}
private void OnProcessed(bool success)
{
if (success)
{
Debug.WriteLine("Item was processed succesfully!");
}
else
{
Debug.WriteLine("Failed to process item!");
}
}
What I'd like to do is have my code block right after the call to 3rdPartyLibObject.Process() and until one of the event handlers fires so I know if the item failed to process or not (and whether I should remove it from the list or not). I'm guessing that this is probably not an uncommon situation but I've never run into it before. Is there a generally agreed upon best practice for dealing with this kind of scenario?

Personally, I would wrap this into a Task<bool>, like so:
Task<bool> Process3rdParty(ThirdPartyLibObject thirdParty, string item)
{
var tcs = new TaskCompletionSource<bool>();
thirdParty.ProcessingComplete += (o, e) => tcs.SetResult(true);
thirdParty.ProcessingFailed += (o, e) => tcs.SetResult(false);
thirdParty.Process(item);
return tcs.Task;
}
You could then call this like so:
private void ProcessListOfItems(List<string> items)
{
while (items.Count > 0)
{
var task = Process3rdParty(thirdPartyLibObject.Process(items[0]);
if (task.Result)
items.Remove(0);
}
}
This would also simplify things if you decided, later, that you wanted this to run asynchronously or to process multiple items at once (if the third party library supports this). This would also be very simple to move to C# 5's async/await support to make the entire thing asynchronous.

Would this work:
private bool itemProcessed = false;
private void ProcessListOfItems(List<string> items)
{
while (items.Count > 0)
{
3rdPartyLibObject.Process(items[0]);
if (itemProcessed)
{
items.Remove(0);
}
}
}
private void obj_ProcessingSuccess(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
this.itemProcessed = true;
}
private void obj_ProcessingFailed(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
this.itemProcessed = false;
}
Assuming the event all fire on the same thread, the handlers should be called before you process the next item.

Related

Unable to modify variables from separate thread

So I'm making a C# app which has to continuously read and display the contents of a text file, while allowing the user to enter something into a text box and append it to the end of that very file.
I'm doing this by running my read method on a separate thread, however changing the variable which stores the display text-files contents is what's causing a problem. Initially I tried having a method which did this, however that's not working and gave a 'cross-thread-operation-not-valid' error. I then tried applying some code I found on MSDN, but now after updating the variable once the thread ended!
Please help.
partial class MainForm
{
delegate void SetTextCallback(string text);
public static string msg;
public static string name;
public void InitClient()
{
name = "public.txt";
Console.WriteLine(name);
if(!File.Exists(name))
{
File.Create(name);
File.AppendAllText(name, "Welcome to " + name);
}
Thread Read = new Thread(new ThreadStart(this.Client));
Read.Start();
while(!Read.IsAlive);
}
public void WriteText()
{
File.AppendAllText(name, this.InputBox.Text);
this.InputBox.Clear();
}
private void SetText(string text)
{
if (this.OutPut.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.OutPut.Text = text;
}
}
public void Client()
{
msg = File.ReadAllText(name);
Console.WriteLine(msg);
Thread.Sleep(300);
this.SetText(msg);
}
}
Why is the thread behaving like this. How can I modify my code so that the contents of the output box always equals that of the text file.
Any suggestions welcome.
You've got multiple problems here,
the use of the File is probably not thread-safe.
your method does not repeat
your are Sleep()ing on a Thread
You can solve all of them by ditching the Thread and use a simple Timer.
Try using a background worker instead of creating a new thread. The background worker will run its content in a seperate thread, and allows you to report 'progress' while its working. This progress report will always be run on the UI-thread (or the thread which started the background worker).
It also has an event which is called when the background worker is finished. This is also run on the UI thread.
This example should get you started.
Update: Added some very basic error handling as suggested
The idea is to use the UserData (2nd argument) of ReportProgress to do updates on the UI thread whenever you need to. In this case it is a string, but this can be any object.
Furthermore, you can use the Result of the DoWorkEventArgs to produce a final result from the background work. In this case, I return any exception which was thrown, or null otherwise, but you can return whatever you want here as well.
It is, as Henk mentioned in his comment, very important to handle errors that occur inside the DoWork callback, because exceptions etc which occurs here will be swallowed and the worker will complete as if nothing bad happened.
private BackgroundWorker _backgroundWorker;
public Form1()
{
InitializeComponent();
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.WorkerSupportsCancellation = true;
// This is the background thread
_backgroundWorker.DoWork += BackgroundWorkerOnDoWork;
// Called when you report progress
_backgroundWorker.ProgressChanged += BackgroundWorkerOnProgressChanged;
// Called when the worker is done
_backgroundWorker.RunWorkerCompleted += BackgroundWorkerOnRunWorkerCompleted;
}
private void BackgroundWorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
if (runWorkerCompletedEventArgs.Result != null)
{
// Handle error or throw it
throw runWorkerCompletedEventArgs.Result as Exception;
}
textBox1.Text = "Worker completed";
}
private void BackgroundWorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs)
{
textBox1.Text = progressChangedEventArgs.UserState as string;
}
private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
try
{
for (int i = 0; i < 100 && !_backgroundWorker.CancellationPending; i++)
{
_backgroundWorker.ReportProgress(0, i + " cycles");
Thread.Sleep(100);
}
}
catch (Exception ex)
{
doWorkEventArgs.Result = ex;
}
}
private void startButton_Click(object sender, EventArgs e)
{
if (!_backgroundWorker.IsBusy)
_backgroundWorker.RunWorkerAsync();
}
private void cancelButton_Click(object sender, EventArgs e)
{
if(_backgroundWorker.IsBusy)
_backgroundWorker.CancelAsync();
}

C# How to stop running backgroundWorker without cancellationPending

is there any way to stop backgroundWorker thread without cancellationPending?
I have code like this:
DoWorkFunction
{
if(worker.cancellationPending == true) return; //this works great but
VeryLongTimeComputingFunc();//this function take a lot of time and if it starts i can't stop it with cancellationPending
...Do something
}
Is there any way to stop worker even if it started VeryLongTimeComputingFunc()?
Maybe you could fire an "CancelWorker" event in your "VeryLongTimeComputingFunc" and in the EventHandler you stop the BackgroundWorker with "worker.CancelAsync()".
This should work:
class BackgroundClass
{
public event EventHandler CancelWorker;
BackgroundWorker worker = new BackgroundWorker();
BackgroundClass()
{
CancelWorker += new EventHandler(BackgroundClass_CancelWorker);
}
void BackgroundClass_CancelWorker(object sender, EventArgs e)
{
worker.CancelAsync();
}
void RunBackgroundWorker()
{
worker.DoWork += (sender, args) =>
{
VeryLongTimeComputingFunction();
};
}
void VeryLongTimeComputingFunction()
{
if (CancelWorker != null)
{
CancelWorker(this, new EventArgs());
}
}
}
This would require that you can change something in the "VeryLongTimeComputingFunction()"
Assuming you can not add proper cancellation support inside VeryLongTimeComputingFunction, your best option is to save a reference to the BGW's thread and call Abort on it.
Keep in mind this is not generally recommended as it may involve a messy cleanup.
To be safe, you should catch any ThreadAbortedException raised in your long function.
private Thread bgThread;
void DoWorkFunction()
{
bgThread = Thread.CurrentThread;
try
{
VeryLongTimeComputingFunc();
}
catch (ThreadAbortedException e)
{
//do any necessary cleanup work.
bgThread = null;
}
}
void CancelBGW()
{
if (bgThread != null)
{
bgThread.Abort();
}
}
Depending on when and how CancelBGW is called, you may also need a lock around assignments of bgThread.

Is it possible to have a common method for background workers?

I have noticed that as the database of my application has grown, the time taken to return results has also increased. In the beginning this was negligible because it was such a small amount of time to return the data source.
Now I am at the point where it temporarily makes the UI unresponsive for a couple of seconds, but I would like to create background workers to do these tasks.
The problem with creating these, is that there are around 9 buttons that would need a background worker and all they do is call a different method in the DLL. Is there any way to use a common method to create these background workers using the API for background workers or should I create an Enum that corresponds to each button and is a parameter taken in by the method that constructs the background worker. Thus meaning I could use a simple switch to execute whatever method from the DLL I choose?
Sample Code:
void bg_DoWorkImports(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
try
{
e.Result = EngineBllUtility.GetNotImportedFiles(connectionString);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void bg_RunWorkerCompletedImports(object sender, RunWorkerCompletedEventArgs e)
{
DataSet temp = (DataSet)e.Result;
if (e.Result != null)
{
importFileGridView.DataSource = temp.Tables[0];
}
}
You could pass an Func<T> to a method that creates a BackgroundWorker and call that action from within to DoWork-event.
Something like this
public class BackgroundWrapper<T>
{
private Func<T> workMethod;
private Action<T> completeMethod;
public static void StartBackgroundworker(Func<T> workMethod, Action<T> completeMethod)
{
BackgroundWrapper<T> bWrap = new BackgroundWrapper<T>();
bWrap.workMethod = workMethod;
bWrap.completeMethod = completeMethod;
bWrap.Start();
}
private void Start()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
completeMethod((T)e.Result);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = workMethod();
}
}
Instead of using BackgroundWorker, an alternative would be to use the TPL. This would let you write the code directly within each member:
void buttonImport_Click(object sender, DoWorkEventArgs e)
{
Task.Factory
.StartNew( () => return EngineBllUtility.GetNotImportedFiles(connectionString))
.ContinueWith( t =>
{
try
{
if (t.Result != null)
{
importFileGridView.DataSource = t.Result.Tables[0];
}
}
catch (AggregateException ex)
{
MessageBox.Show(ex.InnerException.Message);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
Sure, I don't see why you couldn't create a "switchboard" sort of function for that. In fact, you might want to do that, because it would make things a little more modular and promote code reuse.
As far as enums go, personally, I create classes to pass lots of arguments in and out of such things.
I think you need to build some kind of queuing mechanism where one background worker picks up each of the button click jobs and kicks off one after other.

How to avoid spaghetti code when using completion events?

Somehow I cannot believe that I am the first one to run into that problem (and I don't want to believe that I am the only one stupid enough not to see a solution directly), but my search-fu was not strong enough.
I regularly run into a situation, when I need to do a few time-consuming steps one after the other. The workflow looks like
var data = DataGetter.GetData();
var processedData = DataProcessor.Process(data);
var userDecision = DialogService.AskUserAbout(processedData);
// ...
I don't want to block the UI during each step, so every method does return immediately, and raises an event once it has finished. Now hilarity ensues, since the above code block mutates into
DataGetter.Finished += (data) =>
{
DataProcessor.Finished += (processedData) =>
{
DialogService.Finished(userDecision) =>
{
// ....
}
DialogService.AskUserAbout(processedData);
}
DataProcessor.Process(data);
};
DataGetter.GetData();
This reads too much like Continuation-passing style for my taste, and there has to be a better way to structure this code. But how?
The correct way would be to design your components in a synchronous way and execute the complete chain in a background thread.
The Task Parallel Library can be useful for such code. Note that TaskScheduler.FromCurrentSynchronizationContext() can be used to run the task on the UI thread.
Task<Data>.Factory.StartNew(() => GetData())
.ContinueWith(t => Process(t.Result))
.ContinueWith(t => AskUserAbout(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
You can put everything into a BackgroundWorker. The following code would only work properly if you change the methods GetData, Process, and AskUserAbout to run synchronously.
Something like this:
private BackgroundWorker m_worker;
private void StartWorking()
{
if (m_worker != null)
throw new InvalidOperationException("The worker is already doing something");
m_worker = new BackgroundWorker();
m_worker.CanRaiseEvents = true;
m_worker.WorkerReportsProgress = true;
m_worker.ProgressChanged += worker_ProgressChanged;
m_worker.DoWork += worker_Work;
m_worker.RunWorkerCompleted += worker_Completed;
}
private void worker_Work(object sender, DoWorkEventArgs args)
{
m_worker.ReportProgress(0, "Getting the data...");
var data = DataGetter.GetData();
m_worker.ReportProgress(33, "Processing the data...");
var processedData = DataProcessor.Process(data);
// if this interacts with the GUI, this should be run in the GUI thread.
// use InvokeRequired/BeginInvoke, or change so this question is asked
// in the Completed handler. it's safe to interact with the GUI there,
// and in the ProgressChanged handler.
m_worker.ReportProgress(67, "Waiting for user decision...");
var userDecision = DialogService.AskUserAbout(processedData);
m_worker.ReportProgress(100, "Finished.");
args.Result = userDecision;
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs args)
{
// this gets passed down from the m_worker.ReportProgress() call
int percent = args.ProgressPercentage;
string progressMessage = (string)args.UserState;
// show the progress somewhere. you can interact with the GUI safely here.
}
private void worker_Completed(object sender, RunWorkerCompletedEventArgs args)
{
if (args.Error != null)
{
// handle the error
}
else if (args.Cancelled)
{
// handle the cancellation
}
else
{
// the work is finished! the result is in args.Result
}
}

How do I know when my async function is finished? (windows phone7 dev)

This is a Windows Phone7 project.
I have a few async calls in my code, that in the end, fills up a List that is global. But my problem is, how do I know when the async jobs is done, so that I can continue in the code?
EDIT I updated the code:
private void GetFlickrPhotos(Action finishedCallback)
{
Action<FlickrResult<PhotoCollection>> getPhotoCollectionCallback;
getPhotoCollectionCallback = GetPhotoCollection;
flickr.InterestingnessGetListAsync(getPhotoCollectionCallback);
finishedCallback();
}
private void GetPhotoCollection(FlickrResult<PhotoCollection> photoColl)
{
PhotoCollection photoCollection = (PhotoCollection)photoColl.Result;
foreach (Photo photo in photoCollection)
{
flickrPhotoUrls.Add(photo.MediumUrl);
}
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
GetFlickrPhotos(() =>
{
int test = flickrPhotoUrls.Count;
});
}
The async calls is done using Action<T> in .net framework 4. It still doesn't wait for the async call. Is it because the async call is done from "GetFlickrPhotos"?
I went for the following code, it's working for my program. Thank you for the help!
app.Flickr.PhotosSearchAsync(options, flickrResult =>
{
if (flickrResult.HasError)
{
ShowErrorImage();
}
else
{
flickrPhotoUrls.Clear();
flickrImages.Clear();
foreach (var item in flickrResult.Result)
{
FlickrImage image = new FlickrImage();
image.ImageOwner = item.OwnerName;
image.DateTaken = item.DateTaken;
if (item.Title == string.Empty)
{
image.ImageTitle = "Untitled";
}
else
{
image.ImageTitle = item.Title;
}
image.SmallUrl = item.SmallUrl;
image.MediumUrl = item.MediumUrl;
image.Description = item.Description;
image.Latitude = item.Latitude;
image.Longitude = item.Longitude;
if (item.DoesLargeExist == true)
{
image.LargeUrl = item.LargeUrl;
}
flickrImages.Add(image);
}
ShowPhotos();
}
});
This way, I call the method ShowPhotos() when the Flickr call is finished.
In the simplest case, you could provide a callback, or with a little more effort, create an event that raised when the work is complete. Here's code for a callback:
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
DoAsyncWork(()=>{
//continue here
});
}
private void DoAsyncWork(Action finishedCallback)
{
//Doing some async work, and in the end of the last async call,
//a global List<string> myList is filled
//at this point call:
//finishedCallback();
}
Look into IAsyncResult - there are a lot of resources out there related to this particular pattern, but basically this will allow you to maintain an instance of an object who's role it is to allow you to determine the current state of an operation - or even exclusively call an End method to interrupt an operation.
Your method signatures might look something like this, for instance:
public IAsyncResult BeginOperation(AsyncCallback callback)
public EndOperation(IAsyncResult result)
From MSDN:
The IAsyncResult interface is
implemented by classes containing
methods that can operate
asynchronously. It is the return type
of methods that initiate an
asynchronous operation, such as
IsolatedStorageFileStream.BeginRead,
and is passed to methods that conclude
an asynchronous operation, such as
IsolatedStorageFileStream.EndRead. An
IAsyncResult is also passed to the
method that is invoked by an
AsyncCallback delegate when an
asynchronous operation completes.
An object that supports the
IAsyncResult interface stores state
information for an asynchronous
operation, and provides a
synchronization object to allow
threads to be signaled when the
operation completes.
EDIT:
OK, unless I'm missing something then a simple event notification may be all you need here - consider the following usage of a class introduced below:
var flickrOperation = new FlickrOperation();
flickrOperation.FlickrPhotoURLsLoaded +=
delegate(object sender, EventArgs e)
{
var photoCount = flickrOperation.FlickrPhotoURLs.Count;
};
flickrOperation.BeginGetFlickrPhotoURLs();
Now lets define the class, albeit primitive and simply a means to an end in this case. Note, in particular, the declaration an use of FlickrPhotoURLsLoaded - this is the event which is fired upon completed of the operation (as dictated by the completion of the callback loading the URLs):
class FlickrOperation
{
//the result:
//ultimately, hide this and expose a read only collection or something
public List<string> FlickrPhotoURLs = new List<string>();
//the event:
//occurs when all returns photo URLs have been loaded
public event EventHandler FlickrPhotoURLsLoaded;
public void BeginGetFlickrPhotoURLs()
{
//perform the flickr call...
var getPhotoCollectionCallback = GetFlickrPhotoURLsCallback;
flickr.InterestingnessGetListAsync(getPhotoCollectionCallback);
}
private void GetFlickrPhotoURLsCallback(FlickrResult<PhotoCollection> result)
{
//perform the url collection from flickr result...
FlickrPhotoURLs.Clear();
var photoCollection = (PhotoCollection)result.Result;
foreach (Photo photo in photoCollection)
{
flickrPhotoUrls.Add(photo.MediumUrl);
}
//check to see if event has any subscribers...
if (FlickrPhotoURLsLoaded != null)
{
//invoke any handlers delegated...
FlickrPhotoURLsLoaded(this, new EventArgs());
}
}
}

Categories

Resources