How do I pass a function for background worker? - c#

I want to create a function so everytime I can pass the function to call when I need run the function in backgroundWorker. like this.
void RunInBackgroundWorker(Func<object, DoWorkEventArgs, bool> do_work)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += do_work;
worker.ProgressChanged += Worker_ProgressChanged;
worker.WorkerReportsProgress = true;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
But visual studio complain that it cannot implicitly convert type 'System.Func' to 'System.ComponentModel.DoWorkEventHandler'
Is that possible to do it in this way? How to correctly pass the function in?

worker.DoWork += (s, e) => do_work(s, e);
Also this has nothing to do with WPF.

I actually solved it. Instead of passing a funtion (Func do_work), I pass (DoWorkEventHandler do_work) and it works!

Related

how to immediately update displayed textbox before a long loop

My event handler UIButton440_TouchUpInside( UIButton sender ) updates my TextBox.Text then does a long loop, then returns. But Textbox doesn't update until after return.
How can I display the updated TextBox immediately?
(Like vb.net does with application.doEvents)
You can try firing a thread to do your long loop. I usually like using workers for that, something like this:
txt.Text = "abc";
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (o, ea) =>
{
//Long loop
};
worker.RunWorkerCompleted += (o, ea) =>
{
//Do something when the loop ends
};
worker.RunWorkerAsync();
Assuming you're using Windows Forms, you can call the Update method on the TextBox to force a refresh.
yourTextBox.Update();

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.

Backgroundworker's RunWorkerCompleted event is firing even before completing the work

I am using the BackgroundWorker thread to perform a long task(basically reading a big xml file). For the first time the worker works fine as desired, but if I upload a second xml file, using the same background worker it works fine sometimes but most of the time the Backgroundworker's RunWorkerCompleted is fired even before the DoWork event. Some of the code is displayed below
private void openFile_Click(object sender, RoutedEventArgs e)
{
// Code removed for brevity
worker = new BackgroundWorker();
worker.RunWorkerAsync();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.WorkerReportsProgress = true;
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
DataImport();
//worker.Dispose();
//worker.Disposed += new EventHandler(worker_Disposed);
//worker.DoWork -= worker_DoWork;
//worker.RunWorkerCompleted -= worker_RunWorkerCompleted;
//worker = null;
//GC.Collect(GC.GetGeneration(worker), GCCollectionMode.Forced);
}
worker is a globally defined variable. What is wrong here I am not getting. Kindly help
You should add the DoWork-event handler (and all other event handler, too) before calling RunWorkerAsync().
Otherwise, it could happen that RunWorkerAsync does practically nothing.
It should be like this:
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged +=
new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
RunWorkerAsync should be called after subscribing to the DoWork and RunWokerCompleted events.
you should check first that background worker is busy or not, using this....
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
if (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
}
else
{
backgroundWorker1.RunWorkerAsync();
}
As said in https://stackoverflow.com/a/16809596/8029935, you can be blindly assuming that the worker has finished the job and produced a result when DoWork Method dies from an exception. Which is caught by BackgroundWorker and passed to the RunWorkerCompleted event handler as the e.Error property.
So, I suggest you must check that property using a try/catch statement.
If you Call another async function in your BackgroundWorker _DoWork event,
like;
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
somethingsToDoAsync();
// somethingsToDoAsync() function is to ASYNC
}
_RunWorkerCompleted fires even before completed _Dowork event.
Change another function to not async.

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

Background thread in Window_Loaded event threading error

I have to load a window and in Window_Loaded I have to load some variables and show it on Window.
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (o, ea) =>
{
try
{
//code to download some variables which will show on UI of Window Loading
}
catch (Exception ex)
{
//The calling thread cannot access this object because a different thread owns it.
}
};
worker.RunWorkerCompleted += (o, ea) =>
{
};
worker.RunWorkerAsync();
}
But I am getting a threading exception. Is there any way to show the variables value on window from DoWork of Backgroundworker?
You should retrieve the data you need in the DoWork section, then assign it to ea.Result, which will make it available in the RunWorkerCompleted section.
In the RunWorkerCompleted section, you can access ea.Result again, casting the object back to whatever type you assigned in DoWork, and apply the data as needed to your UI controls.
worker.DoWork += (o, ea) =>
{
ea.Result = GetMyData();
};
worker.RunWorkerCompleted += (o, ea) =>
{
var myData = (myDataType)ea.Result;
// Assign myData as needed to UI components...
};
You need to let Dispatcher schedule your code to execute on UI thread and marshal necessary parameters. Try something like this:
Dispatcher.Invoke(
new Action<string>(() =>
{
// Access UI from here
}),
DispatcherPriority.Normal
);
Although this (or something like this, since this is notepad code) will solve your problem, you should consider using MVVM pattern in your implementation. Then you will be able to make changes to ViewModel (just update data) and UI will update accordingly.

Categories

Resources