BackgroundWorker with anonymous methods? - c#

I'm gonna create a BackgroundWorker with an anonymous method.
I've written the following code :
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(
() =>
{
int i = 0;
foreach (var item in query2)
{
....
....
}
}
);
But Delegate 'System.ComponentModel.DoWorkEventHandler' does not take '0' arguments and I have to pass two objects to the anonymous method : object sender, DoWorkEventArgs e
Could you please guide me, how I can do it ?
Thanks.

You just need to add parameters to the anonymous function:
bgw.DoWork += (sender, e) => { ... }
Or if you don't care about the parameters you can just:
bgw.DoWork += delegate { ... }

If you specify a lambda, you must ensure it takes the same number of arguments:
bgw.DoWork += (s, e) => ...;
But if you're not using the arguments, you could just use an anonymous delegate without parameters:
bgw.DoWork += delegate
{
...
};

If you have written the above without lambdas how it would be?
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
and the named method:
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
e.Result = ComputeFibonacci((int)e.Argument, worker, e);
}
But now you are using lambdas with no bound variables ()=>
You should provide two objects sender and e (which they will get type inferred later).
backgroundWorker1.DoWork += (sender, e) => ...

Lets make it simple
Lambda expressions are really handy to make the code shorter and more readable. However entry level programmers might find it a bit difficult to deal with. There are three separate concepts one should go through: anonymous methods, delegates and lambda expressions. A detailed walk-through of each of them is beyond the scope of this answer. I hope that the code example given below will serve the purpose of giving a quick view of the different approaches available.
class TestBed
{
BackgroundWorker bgw = new BackgroundWorker();
void sample()
{
//approach #1
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
//DoWorkEventHandler is nothing but a readily available delegate written by smart Microsoft guys
//approach #2, to make it a little shorter
bgw.DoWork += (s,e) =>
{
//...
};
//this is called lambda expression (see the => symbol)
//approach #3, if lambda scares you
bgw.DoWork += delegate
{
//... (but you can't have parameters in this approach
};
//approach #4, have a helper method to prepare the background worker
prepareBgw((s,e)=>
{
//...
}
);
//approach #5, helper along with a simple delegate, but no params possible
prepareBgw(delegate
{
//...
}
);
//approach #6, helper along with passing the methodname as a delegate
prepareBgw(bgw_DoWork);
//approach #7, helper method applied on approach #1
prepareBgw(new DoWorkEventHandler(bgw_DoWork));
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
//...
}
void prepareBgw(DoWorkEventHandler doWork)
{
bgw.DoWork+= doWork;
}
}
Note that we used "delegate" and not "Delegate" in this example (there is a difference between the two)

Related

Inlining some events in BackgroundWorker?

Im not sure, but is it called inlining when you do it all in one line?
I my code i have this BackgroundWorker. The DoWorker enforce a sleep of on sec and the RunWorkerCompleted just does noe bit of code. Would it be possible to instead of defining a function do it all in one line like
.DoWork += ((sender, arg) => { ... });
and
.RunWorkerCompleted += ((sender, arg...
What is the right syntax for this, and what is this called? Its nice to keep things simple when you have a simple task at hand :-)
You are confusing inlining with lambda expressions.
Inlining is replacing the calling of a method by its body, for example:
int TimesTwo(int x)
{
return x * 2;
}
//before inlining:
int a = TimesTwo(6) + TimesTwo(7);
//after inlining:
int a = 6 * 2 + 7 * 2;
This is a compiler optimization technique to avoid method call overhead.
For your BackgroundWorker example the correct syntax would be:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, e) => RunMyMethod();
//or
worker.DoWork += (sender, e) => { RunMyMethod(); }
For more information see MSDN.

c# - Backgroundworker refusing to do anything for another class

I have a WPF C# projects with the below buttonClick event void:
public void ButtonClick(object sender, RoutedEventArgs e)
{
_worker.WorkerReportsProgress = true;
_worker.DoWork += (o, ea) =>
{
try
{
_class1.hithere();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
};
_worker.ProgressChanged += (o, ea) =>
{
};
_worker.RunWorkerCompleted += (o, ea) =>
{
MessageBox.Show("Done");
};
_worker.RunWorkerAsync();
}
I have a folder in the application called InformationProviders than contains the Class1.cs file and I have implemented the correct using MyApplication.InformationProviders; statement in the MainWindow.xaml.cs file that contains the button click event above.
I have also declared the Class1 class that is then called upon in the backgroundworker DoWork event correctly as such:
readonly Class1 _class1 = new Class1();
The Class1.cs file contains this little code made just to see if it worked and it doesn't unfortunately:
public class Class1
{
public void hithere()
{
MessageBox.Show("Hi, I'm working.");
}
}
What am I missing here???? I declared the class as public and (I believe) declared all that needed to be declared to make the process work...
All it does is display a message saying "Done", meaning it has completed the backgroundworker process (even though it did not do anything at all that was stated in the DoWork event. So pretty much, launching the worker and immediately considering it finished.
Regards and thanks,
Simon
Here's the tricky thing about running a multi-threaded application: only one thread has access to the UI and perform operations on it.
In case of your code, the BackgroudWorker in it's background operation attempts to show a message using MessageBox. This won't work - it's not being "fired" on the UI thread!
If you absolutely MUST perform UI operations from inside the BackgroundWorker (which you shouldn't do - this is what the ProgressChanged event is for) then you can use a Dispatcher class.
Here's a short example:
private void Button_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s, a) =>
{
this.Dispatcher.Invoke(new Action(() => MessageBox.Show("doing stuff")));
};
bw.RunWorkerCompleted += (s, a) =>
{
MessageBox.Show("done");
};
bw.RunWorkerAsync();
}
Also fun fact, if you use Dispatcher.Invoke (as written above), then "doing stuff" will appear first, if you use Dispatcher.BeginInvoke then "done" will appear first, because the other operation will be queued on the UI thread.
Here's the "politically correct" way to use the BackgroundWorker:
bw.WorkerReportsProgress = true;
bw.DoWork += (s, a) =>
{
bw.ReportProgress(0, "doing stuff");
};
bw.ProgressChanged += (s, a) =>
{
MessageBox.Show(a.UserState as String);
};
I found the problem, i was using the Xceed.WPF.toolkit version of the MessageBox and it was just refusing to show that UI element in a backgroundWorker. Thanks for the help though it pointed me in the right direction. hoping this will help other people

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.

c# BeginInvoke Problem

I have a program that makes some hefty calls to the database and then updates the UI. This is causing problems because for most of the time it means that the UI in not responsive. I therefore decided that I wanted to put the function calls that access the database and update the UI in a separate thread, so now I have something like this:
private delegate void CallAsyncDelegate();
private void CallGetDBValues()
{
// Call GetDatabaseValues in new thread
CallAsyncDelegate callGetDatabaseValues = new
CallAsyncDelegate(GetDatabaseValues);
BeginInvoke(callGetDatabaseValues);
}
private void GetDatabaseValues()
{
// Get lots of data here
// Update UI here
}
...
However, it seems to make no difference whatsoever to the UI. I read somewhere that if the code to be run in a separate thread needed to update the UI then this was how the call should be made - is this correct? Am I doing something wrong?
You may be better served using the BackgroundWorker that is built-in to the .NET framework.
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.WorkerReportsProgress = true;
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// update UI with status
label1.Text = (string)e.UserState
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Check for cancel
if(e.Cancelled)
{
//Handle the cancellation.
{
//Check for error
if(e.Error)
{
//Handle the error.
}
// Update UI that data retrieval is complete
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// Get data
//foreach to process data
//Report progress
bw.ReportProgress(n, message);
}
Here's a link to the MSDN article on how to use the BackgroundWorker for additional details. Thanks to Henk Holterman for the suggestion to include this:
http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx
In the "// Update UI here", make sure to use Control.Invoke to actually do the work -- it's imperative that the UI only be "touched" by the UI-thread, and this only happens when you use Control.Invoke.
BeginInvoke and Invoke means to run the code on the UI thread. In this case if you are calling CallGetDBValues() from the UI thread you are not going to gain anything.
Usually you will create a BackgroundWorker or background thread that will do the heavy lifting and it will Invoke back to the UI thread the values that need to be updated.
A BackgroundWorker will probably be the better solution (see Robaticus's answer), but here is a background thread version.
private delegate void CallAsyncDelegate();
private void button_Click( object sender, EventArgs e )
{
Thread thread = new Thread( GetDBValues );
thread.IsBackground = true;
thread.Start();
}
private void GetDBValues()
{
foreach( ... )
{
Invoke( new CallAsyncDelegate( UpdateUI ) );
}
}
private void UpdateUI()
{
/* Update the user interface */
}
I'm not sure of the syntax.. but the sytax I'm more familiar with is something like:
public delegate object myDelegate(object myParam);
Public class MyClass
{
public static void Main()
{
myDelegate d = new myDelegate(myMethod);
d.BeginInvoke ( new object() );
}
static void myMethod(object myParam)
{
// do some work!!
return new object);
}
}

Altering the ObservableCollection according to FileSystemWatcher change notification

I'm trying to update my ObservableCollection as the FileSystemWatcher notifies changes. I know this is not possible because of cross thread operations.
So i would like to get the name of the file created/deleted/renamed when the event is fired and update it in the UI thread once the event is completed, as we do in BackgroundWorker. Can anyone tell me how to do this?
Also tell me where i should define and start this FileSystemWatcher. Currently i've defined it in the MainViewModel.
P.S.: I've seen similar questions in SO, but didn't get a clear picture
Thanks In Advance,
Veer
I would think the main view model is the right place to define the FileSystemWatcher. As for the threading issues, this is the easy way:
_watcher = new FileSystemWatcher(path);
_watcher.Created += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Created event
};
_watcher.Changed += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Changed event
};
_watcher.Renamed += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Renamed event
};
_watcher.Deleted += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Deleted event
};
// ...
_watcher.EnableRaisingEvents = true;
Each of the "Code to handle" will execute within the UI thread so it can update the ObservableCollection. Note that the FileSystemEventArgs "e" is available within this code.
If you prefer to use separate event handler methods you can call them from the above code or use this convenient shortcut:
var switchThread =
(FileSystemEventHandler handler) =>
(object obj, FileSystemEventArgs e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
handler(obj, e))
_watcher = new FileSystemWatcher(path);
_watcher.Created += switchThread(OnCreated);
_watcher.Changed += switchThread(OnChanged);
_watcher.Deleted += switchThread(OnDeleted);
_watcher.Renamed += switchThread(OnRenamed);
_watcher.EnableRaisingEvents = true;
where OnCreated, OnChanged, OnDeleted, and OnRenamed are normal event handler methods with the normal signature, for example:
void OnChanged(object sender, FileSystemEventArgs e)
{
// Code to handle Changed event
}
Personally I prefer the first way of doing it because I don't like creating four extra 1-line methods.
Note that your view model will need to know which Dispatcher to call back on. The easiest way to do this is to derive your view model from DispatcherObject, as assumed above. Another way is for the view model's constructor or the method that registers the FileSystemWatcher events to store a copy of Dispatcher.Current in a local field or local variable, then use that for the .BeginInvoke calls.
Also note that you can use exactly the same code in your view code-behind instead of in your view model if you prefer.
public void SomeActionToBeInvokedOnTheMainThread()
{
if (someControl.Dispatcher.CheckAccess())
{
// you can modify the control
}
else
{
someControl.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(SomeActionToBeInvokedOnTheMainThread)
);
}
}
I used Ray B.'s approach but had to modify things slightly and thought I'd post an update here to maybe save others some time.
My VS2010/.NET 4.0 WPF project was throwing the error:
Cannot assign lambda expression to an implicitly-typed local variable
After some tweaking I came up with the following. Note the additional var defined to handle the Renamed event:
var switchThreadForFsEvent = (Func<FileSystemEventHandler, FileSystemEventHandler>)(
(FileSystemEventHandler handler) =>
(object obj, FileSystemEventArgs e) =>
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
handler(obj, e))));
var switchThreadForFsRenameEvent = (Func<RenamedEventHandler, RenamedEventHandler>)(
(RenamedEventHandler handler) =>
(object obj, RenamedEventArgs e) =>
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
handler(obj, e))));
_fileSystemWatcher = new FileSystemWatcher(documentCollectionPath);
_fileSystemWatcher.Created += switchThreadForFsEvent(OnFileCreated);
_fileSystemWatcher.Deleted += switchThreadForFsEvent(OnFileDeleted);
_fileSystemWatcher.Renamed += switchThreadForFsRenameEvent(OnFileRenamed);
_fileSystemWatcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
_fileSystemWatcher.IncludeSubdirectories = true;
_fileSystemWatcher.EnableRaisingEvents = true;

Categories

Resources