Exception when update a progressbar in a Background Worker - c#

I created a wpf application.
In my application, i open a windows and i copy in background some files.
I would like to display and update a progressbar during thos copy.
I tried to use a BackgroundWorker :
public partial class FenetreProgressBar : Window
{
private readonly BackgroundWorker worker = new BackgroundWorker();
public FenetreProgressBar(ObservableCollection<Evenement.FichierJoint> CollectionFicJointsToAdd)
{
InitializeComponent();
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged +=worker_ProgressChanged;
worker.RunWorkerAsync(CollectionFicJointsToAdd);
}
private void ProgressChanged(double Persentage, ref bool Cancel)
{
if (Cancel)
this.Close();
worker.ReportProgress((int)Persentage);
}
private void Completedelegate()
{
this.Close();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
ObservableCollection<Evenement.FichierJoint> collection = e.Argument as ObservableCollection<Evenement.FichierJoint>;
//2) On ajoute les fichiers joints à l'évènements ( ce qui va donc les copier dans le répertoire paramétré)
foreach (Evenement.FichierJoint FichierJoint in collection)
{
if (FichierJoint.strPathFichier.Length > 0)
{
Evenement.FichierJoint monFichierJoint = new Evenement.FichierJoint(FichierJoint.strPathFichier, App.obj_myEvenement.strEvtNumeroString);
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
monFichierJoint.copyObject.OnProgressChanged += ProgressChanged;
monFichierJoint.copyObject.OnComplete += Completedelegate;
monFichierJoint.AddFichierJoint();
}
}
}
private void worker_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
// Traitement terminé, on ferme la fenetre
this.Close();
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
MaProgressBar.Value = e.ProgressPercentage;
}
}
When the programme go here :
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
I have an exception : " The calling thread cannot access this object because a different thread owns it".
I have read severals answer on google and stackoverflow but i don't try to use this approach with the BackgroundWorker.
Anyone coule help me in order to avoid this exception and solve the problem please ?
Thanks a lot,
Best regards :)

You cannot modify UI objects from background worker. You need to invoke the methods on UI dispatcher like this -
App.Current.Dispatcher.Invoke((Action)delegate
{
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
});
But since you only need to set maximum an minimum values, i would suggest you to set these values outside of backgroundWorker in constructor -
public FenetreProgressBar(ObservableCollection<Evenement.FichierJoint>
CollectionFicJointsToAdd)
{
InitializeComponent();
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged +=worker_ProgressChanged;
worker.RunWorkerAsync(CollectionFicJointsToAdd);
}

Why don't you use C# new async and await new feature/keywords? they were specifically designed to make the UI responsive while doing lengthy operations.

You should try this:
_backgroundWorker.OnProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
and then
// Event handler
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update main thread here
}

Related

how to report about method situation via progress bar wpf C#

i am working on project in C# and its contain a methods that need a long time to be executed so i need a progress bar that tell the user about how much remain and i don't know how .
i google for it and i see courses about BackgroundWorker and still don't know how to use it
private void Lock_Methods()
{
foreach (FolderInfo fi in FolderInfo)
{
// code need a lot of time ....
}
}
any help please ...
Declare
var bw = new BackgroundWorker()
{ WorkerReportsProgress = true };
bw.RunWorkerAsync();
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
And
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
for(int i = 0: i < FolderInfo.Count; i++)
{
//...
(sender as BackgroundWorker).ReportProgress((int)(100/FolderInfo.Count)*i, null);
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}

Can we call method in DoWork event?

I am exporting a Data Table to excel file using background worker. And I wanted to show the export progress using progress bar. Do we have to write the exporting code in Do Work event or can we call a method, which is present in other class.
In my code I tried calling different method. But its not working.
Below is the sample code.
public MainWindow()
{
InitializeComponent();
property = new Property();
this.DataContext = property;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
System.Windows.Forms.MessageBox.Show(e.Error.Message);
}
else
{
System.Windows.Forms.MessageBox.Show("Exported Successfully");
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbStatus.Value = e.ProgressPercentage;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
Export export = new Export();
export.GenerateExcelFile();
}
You need to call worker.ReportProgress from worker_DoWork with a valid progress value
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
worker.ReportProgress(0);
// Some job
worker.ReportProgress(10);
// ...
// Finish
worker.ReportProgress(100);
}
I'm not sure how you are generating report. Further I'm supposing your pbStatus has Minimum="0" and Maximum="100". You can after exporting each row report progress something like that.
worker.ReportProgress(currentRow * 100.0 / totalRows);
You also set your progress bar intermediate if you are not sure how to calculate that by setting progress.IsIndeterminate to true
pbStatus.IsIndeterminate = true;

WinForm new form(waiting) is stuck when opens

I have wcf servise that Update db it is takes 10-15 sec,and i wont to run/show my form with loading/waitting statusbar while servise working, and when service is finished i need to close the watting form.
My problem is when i run ShowDialog(); it is get stuck on it , and don't go to my service.
What i doing wrong here?
My code
My function
public static void UpdateSNXRATES(object sender, EventArgs e)
{
WaitForm waitF = new WaitForm();
waitF.ShowDialog();//here it stuck
using (var Server = new ServiceReference.Service1Client())
{
Server.ClientCredentials.Windows.ClientCredential.Domain = strDomain;
Server.ClientCredentials.Windows.ClientCredential.UserName = strUser;
Server.ClientCredentials.Windows.ClientCredential.Password = strPassword;
success=Server.UpdateSNXRATES();
}
waitF.Close();
}
My WaitForm code
public partial class WaitForm : Form
{
public WaitForm()
{
InitializeComponent();
}
private void WaitForm_Load(object sender, EventArgs e)
{
radWaitingBar1.StartWaiting();
radWaitingBar1.WaitingSpeed = 100;
radWaitingBar1.WaitingStep = 5;
}
}
ShowDialog() is a blocking call, i.e. the current thread will keep waiting on this line until the form is closed (by the user). You should show your WaitForm on a different thread than the main application thread, combined with Invoke() call to ensure that you don't do illegal cross-thread operations. You can use BackgroundWorker component to load and show your WaitForm on a different thread.
Alternately and preferably, you should move your service initialization and running code to the BackgroundWorker. That will ensure you don't need any Invokes.
Example
ServiceReference.Service1Client Server;
WaitForm waitF;
public static void UpdateSNXRATES(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync();
waitF = new WaitForm();
waitF.ShowDialog();
}
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
Server = new ServiceReference.Service1Client();
Server.ClientCredentials.Windows.ClientCredential.Domain = strDomain;
Server.ClientCredentials.Windows.ClientCredential.UserName = strUser;
Server.ClientCredentials.Windows.ClientCredential.Password = strPassword;
success = Server.UpdateSNXRATES();
}
static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitF.Close()
}

backgroundWorker and progressChanged not working

i cant get the progress bar to work! if i execute the following code the bar remains empty even if the code gets executed the ReportProgress doesnt seem to update anything..:
namespace GPUZ_2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
GPUZdata test = new GPUZdata
{
};
//invio l'oggetto al thread backgroundworker
backgroundWorker1.RunWorkerAsync(test);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//
// e.Argument always contains whatever was sent to the background worker
// in RunWorkerAsync. We can simply cast it to its original type.
//
GPUZdata argumentTest = e.Argument as GPUZdata;
argumentTest.OneValue = 6;
Thread.Sleep(2000);
backgroundWorker1.ReportProgress(50);
argumentTest.TwoValue = 3;
Thread.Sleep(2000);
backgroundWorker1.ReportProgress(100);
//
// Now, return the values we generated in this method.
// Always use e.Result.
//
e.Result = argumentTest;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Receive the result from DoWork, and display it.
GPUZdata test = e.Result as GPUZdata;
this.Text = test.OneValue.ToString() + " " + test.TwoValue.ToString();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString();
}
}
}
thanks in advance for your help
To initialize the BackgroundWorker, you must enable progress reporting and hook up your event handlers:
// Enable progress reporting
backgroundWorker1.WorkerReportsProgress = true;
// Hook up event handlers
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
I don't see where you set the WorkerReportsProgress property to true - that most likely is the problem:
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync(test);
I had the same problem. In AssemblyInfo.cs you should make this change for ComVisible.
[assembly: ComVisible(true)]

c# windows form

I have a handler that returns some string messages. How can i put them into a form application? I mean I would like each time the handler is activated to print the result in a windows form. I now i need to use thread. I don't know how can i programatically create and add changes the name of the forms that pop up when a message is handled. Can someone please tell me how to do it?
I asssume that you have some work you want to do in the background and whenever an amount of progress is don you want to update the form...
Then I would use the backgroundworker:
BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
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)); //Activating the progressChanged event
}
}
}
Whenever you execute worker.ReportProgress() the event below will fire on the UI thread which is giving you the dynamic updates you wanted
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}
When the worker is finished executing the RunWorkerCompleted event will fire
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!";
}
}
Source

Categories

Resources