Label is not set until method is done; - c#

I have the following code:
StatusLabel.Content = "Copying files...";
AutoCopy();
StatusLabel.Content = "Finished";
The above code is a button click and when I click the button, I expect to see a label with "Copying files...", then it will copying files via an AutoCopy method and then the label with "Finished"
I do not see "Copying files". All I see is the screen freeze up and then unfreezed with "Finished".
How can I get "Copying files to show..." and only after AutoCopy() is finished, do I want to show "Finished";

As everyone said, your UI (main) thread is blocked during file copy operation.
You need to spin off a worker thread that does everything in the background.
Caution: Multithreading only adds complexity.
{
...
System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RunWorkerCompleted);
StatusLabel.Content = "Copying files...";
bw.RunWorkerAsync();
...
}
private void DoWork(object sender, DoWorkEventArgs e)
{
AutoCopy();
}
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StatusLabel.Content = "Finished";
}

Related

Background worker on login page

I'm doing a simple login form that will show the login process after they click button. It will verify the user access rights and give true or false.
I got an error on this.Hide();
System.InvalidOperationException: 'Cross-thread operation not valid: Control 'formLogin' accessed from a thread other than the thread it was created on.'
Any help would be greatly appreciated. Thanks!!
private void btnLogin_Click(object sender, EventArgs e)
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
PBLogin.Style = ProgressBarStyle.Marquee;
PBLogin.MarqueeAnimationSpeed = 50;
bgw.RunWorkerAsync();
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
PBLogin.Style = ProgressBarStyle.Blocks;
PBLogin.MarqueeAnimationSpeed = 0;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
if (CheckAuthorization())
{
MessageBox.Show("Login Successfully");
TestScript next = new TestScript();
next.Show();
this.Hide();
}
else
{
MessageBox.Show("Login Failed");
}
From a background thread you can't reach the UI, that's what the exception is trying to tell you. In your background thread you should try to focus only on the Authorization logic itself. Try to avoid UI component manipulation.
In the RunWorkerCompleted event you can indeed modify the UI components. So, do the calculation on a dedicated background thread and do the UI manipulation inside the completion event.
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//TODO: Check against e.Error and e.Cancelled before you try to access e.Result
if((bool)e.Result)
{
//UI modification
}
else
{
//UI modification
}
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
var isAuthorized = CheckAuthorization();
e.Result = isAuthorized;
}

How to pass custom EventArgs to UI controls

Unfortunately I was not able to find relevant answer to my problem. I have a object encoder that has an event "VideoEncoding". It passes custom EncodingEventArgs that include various Properties like Progress, Size etc. I can output this info to Console or write to text file. But when I try to utilize it in WinForms I'm not able to pass that information to UI like label or progress bar. I tried different approaches. Background Worker seems like a good idea, The problem is that Background Worker cannot subscribe to VideoEncoding event, neither it will take my custom EventArgs. This is what i was able to put together. Maybe there is a different way to do it using delegates that would communicate with UI. Any suggestions are welcome. Thank you.
public partial class Form1 : Form
{
private BackgroundWorker bw;
int _progress;
public Form1()
{
InitializeComponent();
this.bw = new BackgroundWorker();
this.bw.DoWork += new DoWorkEventHandler(bw_DoWork);
this.bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
this.bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
this.bw.WorkerReportsProgress = true;
this.button1.Click += new EventHandler(button1_Click);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.label1.Text = "The job is: " + e.Result.ToString();
this.button1.Enabled = true;
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.label2.Text = e.ProgressPercentage.ToString() + "% complete";
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
this.Encode
worker.ReportProgress(_progress);
e.Result = "Completed";
}
private void button1_Click(object sender, EventArgs e)
{
if (!this.bw.IsBusy)
{
this.bw.RunWorkerAsync();
this.button1.Enabled = false;
}
}
public void Encode()
{
var job = new EncodingJob();
//setup encoding job
//subscribe to an event
ffmpeg.VideoEncoding += GetProgress;
ffmpeg.DoWork(job);
}
public void GetProgress(object sender, EncodingEventArgs e)
{
_progress = (int)e.Progress;
}
}
Try to call the background workers ReportProgress in the GetProgress Method. How should the form know your progress if you don't signalize it?

Background worker RunWorkerCompleted is never fired

Using the following code my background worker RunWorkerCompleted is never called and I can't figure out why.
void startWaitScan()
{
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// do something here
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("BackgroundWorker1_RunWorkerCompleted");
if (!stopAsync)
{
backgroundWorker1.RunWorkerAsync();
}
}
My goal is for the background worker to run continuously, I had this working in .NET but when I rewrote the code now in C# I'm having this issue.
Do you have all the events hooked up correctly ??
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);

Control number of threads

I have an application which i am add files to my Listbox and run those files.
My application play this files using PcapDot.Net project DLLs and send the packets through the network adapter.
The way is very simple: after all the files added to my application Listbox and the play button clicked the application handle the first file and after this file finished the next file began.
what i want to do is add control to my GUI that control the number of open thread in order to have the ability to play several file simultaneous.
This is my play button event:
private BackgroundWorker bw;
private void btnPlay_Click(object sender, EventArgs e)
{
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
manualResetEvent = new ManualResetEvent(false);
if (bw.IsBusy != true)
bw.RunWorkerAsync();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < listBoxFiles.Items.Counti++) //run in loop all over my listbox
{
// here if have several wiresharkFile events that update my UI:
wiresharkFile.statusChangedEvent += new WiresharkFile.StatusChangedDelegate(
(wFile) =>
{
bw.ReportProgress(wiresharkFile.packetProgressPrecentage, wiresharkFile);
});
wiresharkFile.sendBuffer(); //play the file
}
}
What is the best way to add option to open more than 1 thread in the same time ?
here is a simple example for your use, it shows how to create and sign to an event you'll pop when the thread that open a file ends and then you can, when the event pop, to open another file. make sure you keep a counter and a lock so you won't have race conditions
public delegate void FileClosedHndlr();
public class MyThread
{
private event FileClosedHndlr FileClosed;
public void MyMain()
{
Thread t = new Thread(new ThreadStart(start));
FileClosed += new FileClosedHndlr(MyThread_FileClosed);
t.Start();
}
void MyThread_FileClosed()
{
// Thread has ended file open
// open another file
}
private void start()
{
// Open the file
// End thread
if (FileClosed != null)
{
FileClosed();
}
}
}
it took me a while, so use it

show loading or progress bar in c# winforms

I have windows application in which i need to save data into database and after saving data load crystal report to show report,all this happens on click of save button.
I have button named btn_Submit on click of this data is saved and display report, while saving it takes time so i want to show progress bar for mean time so that user get known that data is in process.how i can do with this windows application.
I gone through this link http://www.codeproject.com/Tips/83317/BackgroundWorker-and-ProgressBar-demo but don't get it exactly I want.
I am aware of background worker but never used it.
I have used background worker and progress bar as given in above link but progress bar does not stop at all once it started.
Can any one help me?can u give any example or link that demonstrate scenario?.
This code i added on Dowork();
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
PrintData arg = (PrintData)e.Argument;
SalesMaster sm = arg.SalesData;
BrokerMaster bm = arg.Broker;
CustomerMaster ctm = arg.Customer;
CompanyMaster cm = arg.Company;
ArrayList hb = arg.Arrardata;
int totunit = arg.totunit;
decimal globalamt = arg.golbamt;
SalesReport sreport = new SalesReport(sm, ctm, cm, bm, hb, totunit, glb_totalamt);
sreport .MdiParent = arg.parentf;
sreport .WindowState = FormWindowState.Maximized;
sreport .Show();
}
i get error on this line sreport .MdiParent = arg.parentf;
This error:
Cross-thread operation not valid: Control 'frmParent' accessed from a thread other than the thread it was created on.
what should be done here?
Suscribe to DoWork and RunWorkerCompleted events and
void btn_Submit_Click(object sender, EventArgs e)
{
btn_Submit.Enabled = false; // disable button while saving report
lbl_Status.Text = "Please wait..";
backgroundWorker.RunWorkerAsync();
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// save report here
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btn_Submit.Enabled = true; // enable button
lbl_Status.Text = "Report saved";
}
Instead of using label, you can show PictureBox with spinner wait image. I don't like to see progress bar, which does not show percentage of task - I expect that when progress bar will be filled, task will be completed. If you really want to use progress bar, then, I'd go with timer component (set timer's interval to desired refresh rate):
void btn_Submit_Click(object sender, EventArgs e)
{
btn_Submit.Enabled = false; // disable button while saving report
timer.Start();
progressBar.Visible = true;
// backgroundWorker.RunWorkerAsync(new object[] { "Foo", 42 });
// backgroundWorker.RunWorkerAsync(new CustomType("Foo", 42));
backgroundWorker.RunWorkerAsync(new { Foo = "Foo", Bar = 42 }););
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// object[] args = (object[])e.Argument;
// CustomType arg = (CustomType)e.Argument;
dynamic arg = (dynamic)e.Argument;
string foo = arg.Foo;
int bar = arg.Bar;
// save report here
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btn_Submit.Enabled = true; // enable button
timer.Stop();
progressBar.Visible = false;
}
void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value == progressBar.Maximum)
{
progressBar.Value = progressBar.Minimum;
return;
}
progressBar.PerformStep();
}
Try to reset the ProgressBar's Value property to 0, like in the code below:
Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
Implemented event handler:
void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Value = 0;
}
To stop or hide the progressbar use background worker's completed event.

Categories