private void bw_DoWork(object sender, DoWorkEventArgs e)
{
loadtest();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Progress Bar Window close
pop.Close();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pop.prgTest.Value = e.ProgressPercentage;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Background Worker code///
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync();
//Progress Bar Window
pop.Show();
}
The load test here is...a method that picks up few images from database and displays them. The method works fine if the run the method on page initialisation but its not giving any output when i load them like this in background worker.....here is the method loadtest.
public void loadtest()
{
string query = "select*from question where id='" + 1 + "'";
MySqlConnection conDataBase = new MySqlConnection(constring);
MySqlCommand cmdDataBase = new MySqlCommand(query, conDataBase);
MySqlDataReader myReader;
try
{
conDataBase.Open();
myReader = cmdDataBase.ExecuteReader();
while (myReader.Read())
{
string qid = myReader.GetInt32("id").ToString();
byte[] imgg1q1 = (byte[])(myReader["question"]);
byte[] imgg2q1 = (byte[])(myReader["opt1"]);
byte[] imgg3q1 = (byte[])(myReader["opt2"]);
byte[] imgg4q1 = (byte[])(myReader["opt3"]);
byte[] imgg5q1 = (byte[])(myReader["opt4"]);
MemoryStream mstreamq1 = new MemoryStream(imgg1q1);
MemoryStream mstream1q1 = new MemoryStream(imgg2q1);
MemoryStream mstream2q1 = new MemoryStream(imgg3q1);
MemoryStream mstream3q1 = new MemoryStream(imgg4q1);
MemoryStream mstream4q1 = new MemoryStream(imgg5q1);
q1.BeginInit();
q1.StreamSource = mstreamq1;
q1.CacheOption = BitmapCacheOption.OnLoad;
q1.EndInit();
// Assign the Source property of your image
q_image.Source = q1;
q1opt1.BeginInit();
q1opt1.StreamSource = mstream1q1;
q1opt1.CacheOption = BitmapCacheOption.OnLoad;
q1opt1.EndInit();
option_1.Source = q1opt1;
q1opt2.BeginInit();
q1opt2.StreamSource = mstream2q1;
q1opt2.CacheOption = BitmapCacheOption.OnLoad;
q1opt2.EndInit();
option_2.Source = q1opt2;
q1opt3.BeginInit();
q1opt3.StreamSource = mstream3q1;
q1opt3.CacheOption = BitmapCacheOption.OnLoad;
q1opt3.EndInit();
option_3.Source = q1opt3;
q1opt4.BeginInit();
q1opt4.StreamSource = mstream4q1;
q1opt4.CacheOption = BitmapCacheOption.OnLoad;
q1opt4.EndInit();
option_4.Source = q1opt4;
}
conDataBase.Close();
}
catch
{
}
}
i am using a background worker to display a popup of loading progressbar until the page loads and popup is a function that will display a new popup window which says loading....
the loadtest method works properly everywhere but its not working with the backgroundworker...the funtion loadtest picks some images from database which takes time and i am displaying a popup until the images are getting loaded and the dispalying in option_2.source,option_2.source,option_3.source and option_4.source..........
Don't change control properties directly from a background thread. Instead send them over to the UI thread in order to use them. One way to do this would be via BackgroundWorker.ReportProgress Method (Int32, Object) see also Updating UI with BackgroundWorker in WPF
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
loadtest(sender as BackgroundWorker);
}
and
public void loadtest(BackgroundWorker bw)
{
//... your code
q1.BeginInit();
q1.StreamSource = mstreamq1;
q1.CacheOption = BitmapCacheOption.OnLoad;
q1.EndInit();
// by freezing the image, it will become available to the UI thread
q1.Freeze();
// Don't directly assign the Source property of your image
// q_image.Source = q1;
// Instead, report progress to the UI thread:
bw.ReportProgress.ReportProgress(25, new Tuple<Image, ImageSource>(q_image, q1));
//... your code
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pop.prgTest.Value = e.ProgressPercentage;
// assign the image source on the UI thread
var data = e.UserState as Tuple<Image, ImageSource>;
data.Item1.Source = data.Item2;
}
Edit: added the Freeze() call to image after initialization. This is necessary in order to allow access to the image outside the worker thread where it was created.
As a side note: Please replace your empty catch { } block with some actual error checking... I suppose you just suppressed the relevant exceptions there that would help in identifying the issues.
The backgroundworker has the ReportProgress method with which you can report periodic progress of the background to the UI.
Set the WorkerReportsProgress to true, as this defaults to false.
bw.WorkerReportsProgress = true;
Then hook up the Progress report event to your UI updating method, bw_ProgressChanged, which you are already doing.
bw.ProgressChanged += bw_ProgressChanged;
Then call in the ReportProgress method wherever you want to update the UI in the Do_Work method. Get the worker from the sender object and pass into the loadtest method and call like below.
bw.ReportProgress(progressPercentage); // This would be % completed you want to display.
This should work.
Related
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?
I want to use a ProgressBar control in C# when my DataGridView is loading data, but when I run my program I get an error:
Cross-thread operation not valid: Control 'dataGridView1' accessed from a thread other than the thread it was created on.
Code:
private readonly BackgroundWorker _bw = new BackgroundWorker();
public workerbloks()
{
InitializeComponent();
progressBar1.MarqueeAnimationSpeed = 30;
// set Visible false before you start long running task
progressBar1.Visible = false;
_bw.DoWork += show_worked_bloks;
_bw.RunWorkerCompleted += BW_RunWorkerCompleted;
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Show();
_bw.RunWorkerAsync();
}
private void BW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Hide();
}
public void show_worked_bloks(object sender, DoWorkEventArgs doWorkEventArgs)
{
MYDBMS md = new MYDBMS();
DataTable dt = new DataTable();
clsWorkBloks clswb = new clsWorkBloks();
try
{
dt = md.ExecuteSelectSQL(clswb.show_all_worked_bloks());
dataGridView1.DataSource = dt;
}
catch
{
}
}
Execute the specified delegate asynchronously on the thread that the dataGridView1 underlying handle was created on.
dataGridView1.BeginInvoke((MethodInvoker)delegate
{
this.dataGridView1.DataSource = dt;
});
As the progressbar is just marquee display. Simply bring it to front before running background worker.
progressBar1.BringToFront();
progressBar1.Show();
_bw.RunWorkerAsync();
I am developing a WPF, C# application and I have to read a very big CSV file and write to a database. This process takes a long time so I want to at least show a progress bar that grows in size as it nears completition.
Now, I have the following code at the top:
private readonly BackgroundWorker worker = new BackgroundWorker();
Then inside the loop I have this:
worker.WorkerReportsProgress = true;
worker.ReportProgress((100 * i) / 10000);
and I have a private sub like this:
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgBar.Value = Math.Min(e.ProgressPercentage, 100);
}
Yet I don't see the progress bar updating or anything happening, program still hangs. Am I doing something wrong?
UPDATE: Tried the MSDN guide here http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx and I somehow failed to get it working with that example. I adjusted the looping part of course. Heh. It still stays idle and nothing updates. Heck, all I want to do is get a small counter that increases every time a line is read and added.
UPDATED CODE:
private BackgroundWorker bw = new BackgroundWorker();
public Process()
{
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 bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Perform a time consuming operation and report progress.
int d = 0;
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
// Set filter for file extension and default file extension
dlg.DefaultExt = ".csv";
dlg.Filter = "CSV File (*.csv)|*.csv";
dlg.Title = "file";
// Display OpenFileDialog by calling ShowDialog method
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
// Open document
string filename = dlg.FileName;
List<String[]> fileContent = new List<string[]>();
using (FileStream reader = File.OpenRead(#filename)) // mind the encoding - UTF8
using (TextFieldParser parser = new TextFieldParser(reader))
{
using (SqlConnection conn = new SqlConnection(Classes.PublicVariables.Connection))
{
parser.Delimiters = new[] { "," };
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
string[] line = parser.ReadFields();
fileContent.Add(line);
SqlCommand comm = QUERYANDPARAMETERS
d += 1;
comm.ExecuteNonQuery();
worker.ReportProgress((d * 10));
}
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblCount.Content = "Complete";
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.lblCount.Content = (e.ProgressPercentage.ToString() + "%");
}
I am getting an excerption when the worker runs.
An exception of type 'System.NullReferenceException' occurred inSolution.exe but was not handled in user code
Additional information: Object reference not set to an instance of an object.
UPDATE3
Got it working! All I needed was the same code as above but this:
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
else
{
bw_DoWork(null, null);
}
In the event handler for the button press.
This will not compile as-is, but should get you started in the right direction:
private readonly BackgroundWorker worker
= new BackgroundWorker { WorkerReportsProgress = true };
public MainWindow()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
}
private void worker_DoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
// Do some long process, break it up into a loop so you can periodically
// call worker.ReportProgress()
worker.ReportProgress(i); // Pass back some meaningful value
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgBar.Value = Math.Min(e.ProgressPercentage, 100);
}
is the varible i int? if it is, the value of (100 * i) / 10000 will return 0 while i < 100. and the param of ReportProgress method should be a precent value. you can change it to worker.ReportProgress(i);,try it.
I have a Crystal Report which generates from various DataTables from a button on a Form with a TreeView. I wanted to run a BackGroundWorker so I can add a ProgressBar, since the Crystal Report generated takes some time. I've read that in the first place I needed to add a BackGroundWorker to the control and put all the logic code that generates que long-running process on the DoWork event of the BackGroundWorker. I did it like this:
//bgwBackThread is the name of the BackGroundWorkerObject
private void bgwBackThread_DoWork(object sender, DoWorkEventArgs e)
{
DataTable reporte = preReportDouble(Ot, Oth);
DataTable hh = reporteHH(Ot, Oth);
DataTable otNoCosto = otNoCost(Ot, Oth);
DataTable dethh = detalleHH(Ot, Oth);
//cryrepo is a Form which holds a CrystalReportViewer
InformeMaquina cryrepo = new InformeMaquina();
cryrepo.Informe = reporte;
cryrepo.Hh = hh;
cryrepo.SinCosto = otNoCosto;
cryrepo.DetHh = dethh;
cryrepo.Show();
}
and after I assigned the method RunWorkerAsync() to the button which generated the Form
before
private void btnReporte_Click(object sender, EventArgs e)
{
bgwBackThread.RunWorkerAsync();
//Below its commented because before of trying BackGroundWorker I just used the code here.
/*DataTable reporte = preReportDouble(Ot, Oth);
DataTable hh = reporteHH(Ot, Oth);
DataTable otNoCosto = otNoCost(Ot, Oth);
DataTable dethh = detalleHH(Ot, Oth);
InformeMaquina cryrepo = new InformeMaquina();
cryrepo.Informe = reporte;
cryrepo.Hh = hh;
cryrepo.SinCosto = otNoCosto;
cryrepo.DetHh = dethh;
cryrepo.Show();
*/
}
The problem is when I press the report button with the code as above. It loads the Form which holds que Crystal Report, but this Forms hangs (even in Debug). Without using BackGroundWorker it works fine, but with delay. I've read that its maybe because I'm loading the Form from a non-UI Thread, and that I have to unbind from the UI and then rebind. Is that the Problem?? If it were, how can I unbind and then rebind??
Your help is very apreciated.
Try creating a private class in your form to hold the DataTable information (which I assume is the time consuming part);
private class ReportTables {
public DataTable reporte;
public DataTable hh;
public DataTable otNoCosto;
public DataTable dethh;
}
Create the DataTables and update the results in the e.Result property:
private void bgwBackThread_DoWork(object sender, DoWorkEventArgs e)
{
ReportTables rt = new ReportTables();
rt.reporte = preReportDouble(Ot, Oth);
rt.hh = reporteHH(Ot, Oth);
rt.otNoCosto = otNoCost(Ot, Oth);
rt.dethh = detalleHH(Ot, Oth);
e.Result = rt;
}
Then in the Completed event, show the form:
void bgwBackThread_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
MessageBox.Show(e.Error.Message);
} else {
ReportsTables rt = e.Result as ReportTables;
//cryrepo is a Form which holds a CrystalReportViewer
InformeMaquina cryrepo = new InformeMaquina();
cryrepo.Informe = rt.reporte;
cryrepo.Hh = rt.hh;
cryrepo.SinCosto = rt.otNoCosto;
cryrepo.DetHh = rt.dethh;
cryrepo.Show();
}
}
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.