Is The reuse of the backgroundworker object possible? - c#

I have a button "refresh" which every time i click on it i want my backgroundworker object to work.
i use
if (main_news_back_worker.IsBusy != true)
{
// Start the asynchronous operation.
main_news_back_worker.RunWorkerAsync();
}
private void main_news_back_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
show_system_urls(urls);
displayNewMes(newMes, newStock, newSource);
displayOldMes(oldMes, oldStock);
}
The first time i use the backgroundworker it work good and also get to the RunWorkerCompleted and do his work.
But the second time i try to run the object the is_busy property of the object is 'true' and i cant run the object again...
Do i need to create a new backgroundworker every time i want to run it? how do i do it?
Thanks.

Yes, no problem. You will however have to make sure that the user cannot click the button again while the BGW is busy. Easily done by setting the Enabled property, stops the button action and provides excellent visual feedback to the user. Try this for example:
private void button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
System.Threading.Thread.Sleep(2000);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
button1.Enabled = true;
}

But the second time i try to run the object the is_busy property of the object is 'true'
That means the first background action is still running.
You will first have to decide if you want 2 of these actions to be going on at the same time.
If No, implement Cancellation so that you can Stop (and then restart) the Bgw.
If Yes, create a new Bgw each time.
And while you can re-use a Bgw, and that makes sense in the 1st scenario, there is no great saving in doing so. The Bgw Thread comes from the ThreadPool and will be re-used anyway.

Related

how to open another form which will have progress bar while UI thread is busy

I tried with background worker. When function with loading database data is called, i call backgroundworker too, and i want to open another form which will have progress bar and when loading data is finished, i want to close that form and let user use app normaly. I tried this
private void SearchBtn_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
//loading data
}
this is function which takes long time to execute so i call background worker.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
f.Show();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
f.Close();
}
f is my form global varibale , when i write like this, i get error that i cant close form which has been opened in another thread. So what im doing wrong.
You must Invoke the method on the thread that owns the control:
Invoke(new Action(() => f.Close()));
Take a look at Invoke method.

Find as you type error backgroundworker in C# winform

I have the following form where I am trying to implement an incremental search on, using a backgroundworker.
So the idea is the user types in the textbox at the top, and for each keystroke, the listview below is filtered to contain only the items that contain the characters the user has typed.
I have recently learnt about the backgroundworker component and was therefore trying to use it to do the filtering and updating the listbox.
This is the event code for the textbox:
private void txtSearch_TextChanged(object sender, EventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}
and the backgroundworker event is:
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (txtSearch.Text != String.Empty)
{
GetTheListOfFiles();
listView.Items.Clear(); << Exception occurs here !
...... //some more code to populate the listview control
}
}
PROBLEM
When I type into the textbox, I was expecting the listbox to respond immediately to my keystrokes and display the filtered data accordingly. Instead, there is a pause of about 8 seconds and then I get this error:
I presume the issue is the bit that I have highlighted, but I have no idea how to solve it. Is it that a backgroundworker cannot be used for this purpose or am I missing something in my implementation?
PS: I welcome any different way to accomplish this. Perhaps there's a better solution out there among more experienced programmers?
UPDATE
Here is the progresschanged event I am using:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
toolStripProgressBar1.Value = e.ProgressPercentage;
tsLabelTwo.Text = e.ProgressPercentage.ToString() + #"%";
}
Thanks
If you create a control using the UI thread, you can't access it thought another thread (eg some background thread)
Just invoke the block that is throwing cross-thread exception on the main thread:
listView.BeginInvoke(new Action(() => { listView.Items.Clear(); }));
If you want to update UI, you need to invoke the control:
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (txtSearch.Text != String.Empty)
{
GetTheListOfFiles();
listView.Dispatcher.BeginInvoke(new Action(() => listView.Items.Clear()), DispatcherPriority.Background);
}
}
This is because you are trying to a control that runs on UI thread from another thread you've created, which is considered illegal. The correct workaround for this is to invoke your control, in this case your ListView.
listView.BeginInvoke(new Action(() =>
{
listView.Items.Clear();
//or perform your UI update or whatever.
}));
But if you wanna be such a rebel and do illegal stuff (sarcasm), add this piece of code right after your InitializeComponents(); method in the form's constructor.
Control.CheckForIllegalCrossThreadCalls = false;
But don't, there is a reason it is called "Illegal Thread Calls" :)
For more information Control.CheckForIllegalCrossThreadCalls Property

Updating the UI right before running the BackgroundWorker

I have this really little problem, but which can't be easily solved. Currently, my program has 2 buttons, a "Start" and a "Cancel". When the user clicks the start, the buttons should go instantly:
StartButton.IsEnabled = false;
CancelButton.IsEnabled = true;
But this occurs only when the BackgroundWorker has finished (all the code which will be ran after pressing the button), because the UI is always updated as last. There's no way I could add these commands to the "ProgressChanged" or "Completed" event of the backgroundworker. These events can take up to 10min to complete.
One easy way is to add these commands to the "ProgressChanged" part, and in the end "Complete" change their state again. But I'd like to avoid this, as the buttons should be showing their real state all the time, not after few "ProgressChanged" events. Of course there's always ways around, like not using the button's UI properties.
Is there any short solution for this?
It doesn't work to add the Button.Property changes to the ClickEvent. That's the main problem in this. I can easily use the "Completed" part of BGW to change the Button's back to match the starting state. The problem is to get them set right before all the events and BGW.
if you have a start button like:
this.StartButton = new System.Windows.Forms.Button();
then you can do
this.StartButton.Click += new System.EventHandler(this.button1_Click);
and then do
private void button1_Click(object sender, EventArgs e)
{
StartButton.IsEnabled = false;
CancelButton.IsEnabled = true;
Thread bg = new Thread(new ThreadStart( UpdateDatabase()));
bg.Start();
}
if you want the bg thread to send messages to the UI use the Invoke method like here
public delegate void UpdateUIHndler();
public void UpdateUI()
{
}
and do
if (InvokeRequired)
{
Invoke(new UpdateUIHndler(UpdateUI));
}
Take a look at a previous question of mine (quite similer). I should go for option 1.
ASP.NET Application log while code is running / progress bar
UI will only be delayed 5 seconds. Instead of text update the button styling using AJAX.
you can disable the start button in the click event of that button itself and enable it again it on RunWorkerCompleted event of BGW as shown below
BackgroundWorker _worker = new BackgroundWorker();
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
private void StartButton_Click(object sender, RoutedEventArgs e)
{
startButton.IsEnabled = false;
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
stratButton.IsEnabled = true;
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
//Your processing code
}

Removing from ListBox inside of a Timer

ObservableCollection<String> listBoxItems = new ObservableCollection<String>();
scheduledRecordingListBox.ItemsSource = listBoxItems;
public void timerElapsed(object sender, ElapsedEventArgs e)
{
listBoxItems.Remove(itemToBeRemoved);
}
Just a snippet of what I'm actually trying to do. I believe the error is caused because the timer is running on a different thread than the GUI main thread that the ObservableCollection I'm trying to remove from is.
If you are using WinForms, then just use the System.Windows.Timer class. It's Tick event is automatically executed on the UI thread.
This should do the Trick:
public void timerElapsed(object sender, ElapsedEventArgs e)
{
this.Invoke(new Action(() => listBoxItems.Remove(itemToBeRemoved)));
}
Try using Invoke it executes a delegate on the thread that owns the control's underlying window handle.
You can also have a look of the section timers in this page

ShowDialog, PropertyGrid and Timer problem

I have a strange bug, please, let me know if you have any clues about the reason.
I have a Timer (System.Windows.Forms.Timer) on my main form, which fires some updates, which also eventually update the main form UI. Then I have an editor, which is opened from the main form using the ShowDialog() method. On this editor I have a PropertyGrid (System.Windows.Forms.PropertyGrid).
I am unable to reproduce it everytime, but pretty often, when I use dropdowns on that property grid in editor it gets stuck, that is OK/Cancel buttons don't close the form, property grid becomes not usable, Close button in the form header doesn't work.
There are no exceptions in the background, and if I break the process I see that the app is doing some calculations related to the updates I mentioned in the beginning.
What can you recommend? Any ideas are welcome.
What's happening is that the thread timer's Tick method doesn't execute on a different thread, so it's locking everything else until it's done. I made a test winforms app that had a timer and 2 buttons on it whose events did this:
private void timer1_Tick(object sender, EventArgs e)
{
Thread.Sleep(6000);
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
frmShow show = new frmShow();
show.ShowDialog(); // frmShow just has some controls on it to fiddle with
}
and indeed it blocked as you described. The following solved it:
private void timer1_Tick(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(DoStuff);
}
private void DoStuff(object something)
{
Thread.Sleep(6000);
}

Categories