This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to use a backgroundworker?
Please point me in to good description of how to use backgroundworker or what I must to use to keep gui from freezing while app does some long process?
Gui freezes when I do pinging process or whatever.. it's just annoying, I would like to display results of pinging different hosts while it pings it, but it's frozen untill it stops pinging all hosts in a list.
Here is an example:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace SL_BackgroundWorker_CS
{
public partial class Page : UserControl
{
private BackgroundWorker bw = new BackgroundWorker();
public Page()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 10); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress((i * 10));
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.tbProgress.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.tbProgress.Text = ("Error: " + e.Error.Message);
}
else
{
this.tbProgress.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}
}
}
BackgroundWorker worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();//Calls worker_DoWork on a separate thread.
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)//Runs when worker_DoWork is completed.
{
//
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//
}
Related
I am using BackgroundWorker for my WPF application, but what is in the Worker_RunDetection function does not work and there is no interface update from Worker_ProgressShow. Worker_ProgressShow is for updating interface and Worker_RunDetection processes images from path I got from user. This application must search for text in images and tell user how many images have already been processed. What`s wrong?
UPD: I used RunWorkerCompleted and got
The calling thread cannot access this object, because another thread owns it.
Not I use Dispatcher.Invoke, but interface freeze. Progress is a component (ProgressBar).
int numberProcessed = 0;
private void MainForm_ContentRendered(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_RunDetection;
worker.ProgressChanged += Worker_ProgressShow;
}
private void Worker_ProgressShow(object sender, ProgressChangedEventArgs e)
{
this.Dispatcher.Invoke(() => {
Progress.Value = Convert.ToInt32(e.UserState);
if (Progress.Value % 10 == 0)
LogTextBox.Text += $"\n{Progress.Value} images are processed";
});
}
private void Worker_RunDetection(object sender, DoWorkEventArgs e)
{
this.Dispatcher.Invoke(() => {
foreach (String imageFileName in Directory.GetFiles(PathTextBox.Text))
{
detector = new ImageProcessing(isFolder, imageFileName, pathFolder);
detector.DetectTextOnImage();
numberProcessed++;
(sender as BackgroundWorker).ReportProgress(numberProcessed);
}
});
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
if (PathTextBox.Text != "")
{
worker.RunWorkerAsync();
}
}
Problem was with the Apth taken from PathTextBox.Text.
It must not reference Controls declared in the UI Thread in the DoWork() handler of a BackGroundWorker.
Everything works fine if the task logic is separated from the UI.
Corrected code:
int numberProcessed = 0;
private void MainForm_ContentRendered(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_RunDetection;
worker.ProgressChanged += Worker_ProgressShow;
}
private void Worker_ProgressShow(object sender, ProgressChangedEventArgs e)
{
Progress.Value = Convert.ToInt32(numberProcessed);
if (Progress.Value % 10 == 0)
LogTextBox.Text += $"\n{Progress.Value} images are processed";
}
private void Worker_RunDetection(object sender, DoWorkEventArgs e)
{
foreach (String imageFileName in Directory.GetFiles(e.Argument.ToString()))
{
detector = new ImageProcessing(isFolder, imageFileName, pathFolder);
detector.DetectTextOnImage();
numberProcessed++;
(sender as BackgroundWorker).ReportProgress(numberProcessed);
}
}
I'm dealing with a thread error using a worker in my function. I already checked about bindings and 'invoke'(?) but I'm quite new to C# and WPF and I don't really understand the way I should solve this. It seems that I'm calling of function from another which is not the "owner".
void myLongLastingFunction(0)
{
line_list.SelectedIndex = 0; //ERROR CrossThread
blablabla..
}
private void btnClick(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoConvertOne;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerAsync();
}
private void worker_DoConvertOne(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
//Processing
myLongLastingFunction(0);
//The progress bas is full...
worker.ReportProgress(100, "Done Processing.");
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Converting finished!");
TestProgressBar.Value = 0;
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
TestProgressBar.Value = e.ProgressPercentage;
}
I was inspired by this post.
Error appears when I'm calling myLongLastingFunction() which is crashing my app :
System.InvalidOperationException: 'Calling thread can't reach this object because a other thread is the owner'
Sorry for my translation which is probably faulse but as close to the original message as possible.
Have you got any idea ?
Use the dispatcher:
void myLongLastingFunction(0)
{
Dispatcher.BeginInvoke((Action)(() => {
line_list.SelectedIndex = 0;
}));
}
I want to run a progress bar on a form through the use of a timer.
I have tried multiple ways and have not been able to get it to work.
I hope someone here can help me with this.
private void SplashScreen_Load(object sender, EventArgs e)
{
splashScreenTimer.Enabled = true;
splashScreenTimer.Start();
splashScreenTimer.Interval = 1000;
progressBar.Maximum = 100;
splashScreenTimer.Tick += new EventHandler(timer1_Tick);
}
private void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value != 10)
{
progressBar.Value++;
}
else
{
splashScreenTimer.Stop();
}
}
you are assigning event_handler like
splashScreenTimer.Tick += new EventHandler(timer1_Tick);
and you are changing the progressBar value in
private void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value != 10)
{
progressBar.Value++;
}
else
{
splashScreenTimer.Stop();
}
}
change event handler to
splashScreenTimer.Tick += new EventHandler(timer_Tick);
or move codes to the other event handler timer1_Tick which should be in your form
For running the progressBar full in 4 seconds you can do like this
private void Form1_Load(object sender, EventArgs e)
{
splashScreenTimer.Enabled = true;
splashScreenTimer.Start();
splashScreenTimer.Interval = 30;
progressBar.Maximum = 100;
splashScreenTimer.Tick += new EventHandler(timer_Tick);
}
int waitingTime = 0;
private void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value < 100)
{
progressBar.Value++;
}
else
{
if (waitingTime++ > 35)
this.Close();
}
}
I am working with threads in C#. Below is the code which I am using
// worker thread
Thread m_WorkerThread;
// events used to stop worker thread
ManualResetEvent m_EventStopThread;
ManualResetEvent m_EventThreadStopped;
private void btnSend_Click(object sender, EventArgs e)
{
if (btnSend.Text == "Cancel")
{
StopThread();
btnSend.Text = "Send";
return;
}
else
{
// initialize events
m_EventStopThread = new ManualResetEvent(false);
m_EventThreadStopped = new ManualResetEvent(false);
btnSend.Text = "Cancel";
// reset events
m_EventStopThread.Reset();
m_EventThreadStopped.Reset();
// create worker thread instance
m_WorkerThread = new Thread(new ThreadStart(this.ThreadFunction));
m_WorkerThread.Name = "Thread Sample"; // looks nice in Output window
m_WorkerThread.Start();
}
}
private void StopThread()
{
if (m_WorkerThread != null && m_WorkerThread.IsAlive) // thread is active
{
// set event "Stop"
m_EventStopThread.Set();
// wait when thread will stop or finish
try
{
Thread.Sleep(1000);
m_WorkerThread.Abort();
m_WorkerThread.Suspend();
}
catch { }
}
ThreadFinished(); // set initial state of buttons
return;
}
private void ThreadFunction()
{
// Doing My Work
}
private void ThreadFinished()
{
btnSend.Text = "Send";
}
The code above is working fine, but I have some problems.
When the threads end, btnSend.Text = "Send" is not setting.
When I press cancel, the the threads are not ending properly.
When I press cancel and close my application, the application keeps running in the background.
How can I fix these problems?
This is an example of how to use a BackgroundWorker with cancellation:
public partial class Form1 : Form
{
bool _isWorking = false;
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void button1_Click(object sender, EventArgs e)
{
if (_isWorking)
{
// Cancel the worker
backgroundWorker1.CancelAsync();
button1.Enabled = false;
return;
}
_isWorking = true;
button1.Text = "Cancel";
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (var i = 0; i < 10; i++)
{
if (backgroundWorker1.CancellationPending) { return; }
Thread.Sleep(1000);
}
e.Result = "SomeResult";
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_isWorking = false;
button1.Enabled = true;
button1.Text = "Run";
if (e.Cancelled) return;
// Some type checking
string theResult = e.Result as string;
if (theResult == null) return; // Or throw an error or whatever u want
MessageBox.Show(theResult);
}
}
I have a WPF form which runs a background operation with progress bar. but the problem is that;
when the operation is completed, the progress bar is still running. I mean it shows like the operation is in progress.
how can I stop that? here is my whole code;
System.ComponentModel.BackgroundWorker mWorker;
private void button1_Click(object sender, RoutedEventArgs e) {
mWorker = new System.ComponentModel.BackgroundWorker();
mWorker.DoWork +=new System.ComponentModel.DoWorkEventHandler(worker_DoWork);
mWorker.ProgressChanged +=new System.ComponentModel.ProgressChangedEventHandler(worker_ProgressChanged);
mWorker.WorkerReportsProgress = true;
mWorker.WorkerSupportsCancellation = true;
mWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
mWorker.RunWorkerAsync();
while (pbProcessing.Value != 100) {
if (!mWorker.CancellationPending) {
try {
pbProcessing.Value = (pbProcessing.Value + 0.01) % 100;
} catch (System.Exception ex) {
// No action required
}
} else {
MessageBox.Show(this, "Process cancelled", "Cancel Process", MessageBoxButton.OK);
break;
}
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new System.Threading.ThreadStart(delegate { }));
}
}
private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
// Do your work here, its on seperate thread
System.Threading.Thread.Sleep(10000);
}
private void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
pbProcessing.Value = e.ProgressPercentage;
}
private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
// Stop Progressbar updatation
Window1 w = new Window1();
w.Browser.Navigate(new Uri("http://stackoverflow.com"));
w.Show();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (mWorker != null) {
if (mWorker.IsBusy) {
mWorker.CancelAsync();
}
}
}
If you want to hide the progressbar after the work is done, set its Visibility property to Visibility.Hidden. If you just want to reset it to its initial state, set it's Value to 0 (or to pbProgressing.Minimum, if you changed that from its default value).
As a side note, your code doesn't really make sense: Instead of continuously changing pbProcessing.Value in the button event handler (which is completely useless, since no UI updates are performed until the button event handler has completed), you should only change the value in ProgressChanged. I.e., your code should look something like this:
System.ComponentModel.BackgroundWorker mWorker;
private void button1_Click(object sender, RoutedEventArgs e) {
mWorker = new System.ComponentModel.BackgroundWorker();
mWorker.DoWork +=new System.ComponentModel.DoWorkEventHandler(worker_DoWork);
mWorker.ProgressChanged +=new System.ComponentModel.ProgressChangedEventHandler(worker_ProgressChanged);
mWorker.WorkerReportsProgress = true;
mWorker.WorkerSupportsCancellation = true;
mWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
mWorker.RunWorkerAsync();
// Don't do anything else here
}
private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
for (int i = 1; i < 100; i++) {
mWorker.ReportProgress(i);
// Do some part of the work
System.Threading.Thread.Sleep(100);
// Check if the user wants to abort
if (mWorker.CancellationPending) {
e.Cancel = true;
return;
}
}
mWorker.ReportProgress(100); // Done
}
private void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
pbProcessing.Value = e.ProgressPercentage;
}
private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
// Stop Progressbar updatation
Window1 w = new Window1();
w.Browser.Navigate(new Uri("http://stackoverflow.com"));
w.Show();
// Check the result
if (e.Cancelled) {
// show the message box that the task has been canceled
}
// Reset Progress bar
pbProcessing.Value = 0;
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (mWorker != null) {
if (mWorker.IsBusy) {
mWorker.CancelAsync();
}
}
}