I have a stopwatch running in a different thread, that updates the GUI thread in a label to show as time goes by. When my program closes, it throws a ObjectDisposedException when I call this.Invoke(mydelegate); in the Form GUI to update the label with the time from the stopwatch.
How do I get rid of this ObjectDisposedException?
I have tried to stop the stopwatch in the FormClosing Event, but it does not handle it.
Here's the code:
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
stopwatch = sw;
sw.Start();
//System.Threading.Thread.Sleep(100);
System.Threading.Thread t = new System.Threading.Thread(delegate()
{
while (true)
{
TimeSpan ts = sw.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
timeElapse = elapsedTime;
UpdateLabel();
}
});
stopwatchThread = t;
t.Start();
public void UpdateLabel()
{
db = new doupdate(DoUpdateLabel);
this.Invoke(db);
}
public void DoUpdateLabel()
{
toolStripStatusLabel1.Text = timeElapse;
}
What it looks like is the Stopwatch is being disposed when you close your application, but the thread is still running and trying to use it. Can you stop your thread first before closing the application (in the FormClosing event)?
Same code, now using a BackgroundWorker and an orderly shutdown that ensures the form doesn't close until the background thread has stopped running first:
using System;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.WorkerReportsProgress = backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerAsync();
}
bool mCancel;
void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
if (e.Error != null) MessageBox.Show(e.Error.ToString());
if (mCancel) this.Close();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
if (backgroundWorker1.IsBusy) mCancel = e.Cancel = true;
backgroundWorker1.CancelAsync();
}
void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
label1.Text = e.UserState as string;
}
void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
Stopwatch sw = Stopwatch.StartNew();
while (!backgroundWorker1.CancellationPending) {
TimeSpan ts = sw.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
backgroundWorker1.ReportProgress(0, elapsedTime);
Thread.Sleep(15);
}
}
}
}
Note that the Sleep() call is required, it isn't possible to marshal calls to the UI thread more than about a 1000 times per second.
Related
In my C# windows form, I want to set notification label with loop and thread before fill the data into data grid view . for that I try to use below method and thread.
My Thread is
public void Run()
{
System.Windows.Forms.MessageBox.Show("this is System Thread");
m = new Dashboard();
string text = "";
Int32 a = 0;
do
{
Thread.Sleep(1000);
notiCount++;
/*Notifications ne = new Notifications(m.loadNotification);
ne.Invoke(text);*/
//Thread.Sleep(1000);
}
while (notiCount <= 10) ;
}
My method is
private void loadINtransfer(string status)
{
Int32 x = 0;
string text="";
SystemThreadings s = new SystemThreadings();
Thread t = new Thread(s.Run);
t.Start();
Thread.Sleep(100);
do
{
if (s.notiCount == 0)
{
text = "Request Data";
Thread.Sleep(1000);
this.loadNotification(text);
// MessageBox.Show("request");
}
else if (s.notiCount == 3)
{
text = "Fetching Data";
Thread.Sleep(1000);
//MessageBox.Show("request");
this.loadNotification(text);
}
else if (s.notiCount == 6)
{
text = "Loading Data";
Thread.Sleep(1000);
this.loadNotification(text);
//MessageBox.Show("loading");
}
else if (s.notiCount == 9)
{
text = "Done";
Thread.Sleep(1000);
this.loadNotification(text);
//MessageBox.Show("done");
}
//Thread.Sleep(200);
}
while (s.notiCount != 10);
//Thread.Sleep(5000);
MessageBox.Show("attach");
dt = dl.loadTransfer(status);
dgvDashboard.AutoGenerateColumns = false;
dgvDashboard.DataSource = dt;
}
but it only show Done part. other if parts are passing but not show. And I want to wait some time the all parts before load data to grid view. how can I do this. Please help Me.
As I alluded to in the comments, this is pretty well a poster-child use case for BackgroundWorker. I created a new Windows Forms application, added a button and a label (I didn't bother to rename them), and then double-clicked the button to add an event handler. After adding the BackgroundWorker code, this is what Form1.cs ended up looking like:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.WorkerReportsProgress = true;
bw.ProgressChanged += Bw_ProgressChanged;
bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("attach");
//dt = dl.loadTransfer(status);
//dgvDashboard.AutoGenerateColumns = false;
//dgvDashboard.DataSource = dt;
}
private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 0)
{
label1.Text = "Request Data";
}
else if (e.ProgressPercentage == 3)
{
label1.Text = "Fetching Data";
}
else if (e.ProgressPercentage == 6)
{
label1.Text = "Loading Data";
}
else if (e.ProgressPercentage == 9)
{
label1.Text = "Done";
}
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int notiCount = 0;
do
{
Thread.Sleep(1000);
notiCount++;
worker.ReportProgress(notiCount);
}
while (notiCount <= 10);
}
}
}
Notice that we're not having to sleep or wait on the UI thread. When progress has been made, we're notified and can access the UI to update it. And when the work is complete, we again get notified.
The only Thread.Sleep we have is within the background worker, and I assume there is standing for actual useful work being done.
You absolutely should not have any Thread.Sleep calls in any constrained context such as the UI thread, where there aren't likely to be any other threads available to service other uses which may want to use your thread whilst you're just blocking it. Even Sleeping a threadpool thread is acting as a bad "team player" in modern multi-threaded applications.
The C# window which performs a data pull from SQL stored procedure, doesn't show 'Time Elapsed' because the Timer control doesn't seem to work.
One of my applications, that uses Timer control - doesn't seem to keep the timer ticking when it's processing.
If I perform Timer.Start() on Form_Load, it seems to work fine. However Timer.Start() prior to starting of a data pull (which takes about 2-3 minutes) seems to not-work.
Timer is enabled.
private void btnCalculate_Click(object sender, EventArgs e)
{
tmrTime.Start();
if (txtEmployeeNumber.Text.Trim() != "")
{
dtStart = DateTime.Now;
connectDB(); //Connects to Database, Executes a Stored Procedure, Prepares a response String, and assigns response to a Textbox. All of which takes 2-3 minutes.
}
else
{
MessageBox.Show("Please enter a value!");
}
tmrTime.Stop();
}
private void tmrTime_Tick(object sender, EventArgs e)
{
txtTimer.Text = "Time Elapsed : " + (DateTime.Now - dtStart).Seconds + " second(s)";
}
Should do this
var sw = Stopwatch.StartNew();
// here execute your DB call
sw.Stop();
txtTimer.Text = string.Format("Time Elapsed : {0}", sw);
Now, if you do this via background thread, your screen should be responsive. Just make sure to synchronize control (text box). You can start with BackgroundWorker and do this on DoWork. Then on complete, read data and set control value
UPDATE
If you want time of execution show on form, do this. This is all you need
public partial class Form1 : Form
{
Timer _timer = new Timer();
private DateTime _startTime;
public Form1()
{
InitializeComponent();
_timer.Interval = 1000;
_timer.Tick += _timer_Tick;
}
void _timer_Tick(object sender, EventArgs e)
{
var span = (DateTime.Now - _startTime);
label1.Text = string.Format("Elapsed: {0}", span);
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "";
_startTime = DateTime.Now;
_timer.Start();
var bgw = new BackgroundWorker();
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerAsync();
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_timer.Stop();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// run query here
}
}
Maybe better solution would be to use Stopwatch?
Check here: https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch(v=vs.110).aspx
EDIT:
After Steve's comment - I added some usability for Stopwatch class
static void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
DoSomething();
sw.Stop();
Console.WriteLine($"DoSomething() code took {sw.ElapsedMilliseconds}ms to run.");
sw.Restart();
DoSomethingElse();
sw.Stop();
Console.WriteLine($"DoSomethingElse() code took {sw.ElapsedMilliseconds}ms to run.");
}
Note - watch out for weird calculations while debugging - it will continue to count as you put a breakpoint at spots in your code.
I have a background worker used for running a time consuming sync operation with server and is working perfectly and UI is responsive during the operation
BackgroundWorker syncWorker = new BackgroundWorker();
syncWorker.WorkerReportsProgress = true;
syncWorker.DoWork += new DoWorkEventHandler(syncWorker_DoWork);
syncWorker.ProgressChanged += new ProgressChangedEventHandler(syncWorker_ProgressChanged);
syncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(syncWorker_RunWorkerCompleted);
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (xxxx item in actives)
{
target.ReportProgress(progress);
//time taking event running fine here..
}
target.ReportProgress(90);
}
private void syncWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lbl_progress.Text="Wait......";
}
private void syncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbl_progress.Text="DONE!..";
}
Now i have to do a file download operation and i am using Webclient to do it using the code
WebClient downloadClient = new WebClient();
downloadClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(downloadClient_DownloadProgressChanged);
downloadClient.DownloadFileCompleted += new AsyncCompletedEventHandler(downloadClient_DownloadFileCompleted);
downloadClient.DownloadFileAsync(new Uri(fileUrl), download_path);
void downloadClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
int progress_value = int.Parse(Math.Truncate(percentage).ToString());
progress_value = (progress_value < 5) ? 5 : (progress_value > 95) ? 95 : progress_value;
lblDownloadProgress.Content = string.Format("DOWNLOADING - {0}%", progress_value.ToString());
}
void downloadClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
string item = (string)e.UserState;
if (e.Error != null )
{
lblDownloadProgress.Content = "Unable to download.Try again.....";
lblDownloadProgress.Foreground = Brushes.Red;
}
else if (e.Cancelled)
{
//Do Nothing
}
else
{
lblDownloadProgress.Content ="DOWNLOADED..";
}
}
Now can i run these 2 things parallely ? Like run background worker while downlaoding the file??
if file downloading finished first wait till the completion of background worker
if background worker finished first wait till completion of download
Enable controls after both operations finished and keep UI responsive during the whole time
You can run 2 Background worker in parallel but if you need check the state of one of them you can check if the backgroundworker is busy(doing work or completed).
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
while( downloadClient.IsBusy)
{
Sleep(5000);
//waiting downloadClient worker to complete
}
//continue the work
}
look into this for check some trick you can do.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading;
namespace download_demo
{
class Program
{
static void Main(string[] args)
{
BackgroundWorker MyWorker = new BackgroundWorker();
MyWorker.DoWork += MyWorker_DoWork;
MyWorker.RunWorkerCompleted +=MyWorker_RunWorkerCompleted;
MyWorker.RunWorkerAsync();
Console.ReadKey();
}
private static void MyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("both job completed");
}
private static void MyWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread download = new Thread(DownloadJob);
download.Start();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(20);
Console.WriteLine("doing some job while downloading ");
}
Console.WriteLine("waiting the end of download......... ");
download.Join();
}
private static void DownloadJob(object path)
{
/// process download the path
///simulate 20 seconde of download
for(int i = 0;i<100;i++)
{
Thread.Sleep(50);
Console.WriteLine("downloaded :" + i + " Ko");
}
}
}
}
I hav tried the below code for checking reports from server in every 30seconds,but after 30seconds tick,The application hangs for several seconds.How to avoid the Hanging problem.
The below code am tried,what change want to given in this?
System.Windows.Threading.DispatcherTimer dispatcherTimer2 = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer2.Tick += new EventHandler(dispatcherTimer2_Tick);
dispatcherTimer2.Interval = new TimeSpan(0, 0, 30);
Public void dispatcherTimer2_Tick(object sender, EventArgs e)
{
dispatcherTimer2.start();
//code for function call autoreport();
}
DispatcherTimer callback is executed on main UI thread and blocks it.
Use System.Threading.Timer and if you need to update user interface from timer callback use one of
Dispatcher.Invoke
overloads.
In code something like this
public partial class MainWindow : Window
{
System.Threading.Timer timer;
public MainWindow()
{
InitializeComponent();
timer = new System.Threading.Timer(OnCallBack, null, 0, 30 * 1000);
}
private void OnCallBack(object state)
{
//code to check report
Dispatcher.Invoke(() =>
{
//code to update ui
this.Label.Content = string.Format("Fired at {0}", DateTime.Now);
});
}
}
var timer = new System.Threading.Timer(
delegate
{
//--update functions here (large operations)
var value = Environment.TickCount;
//--run update using interface thread(UI Thread)
//--for WinForms
Invoke(
new Action(() =>
{
//--set the value to UI Element
}));
//--for WPF
Dispatcher.Invoke(
new Action(() =>
{
//--set the value to UI Element
}), null);
});
var period = TimeSpan.FromSeconds(30);
timer.Change(period, period);
I hope it helps.
This is worked for me
public Form1()
{
InitializeComponent();
var timer = new System.Timers.Timer(500);
// Hook up the Elapsed event for the timer.
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Invoke(
new Action(() =>
{
label1.Text += "Test Label";
Application.DoEvents();
}));
}
In my application I need to perform a series of initialization steps, these take 7-8 seconds to complete during which my UI becomes unresponsive. To resolve this I perform the initialization in a separate thread:
public void Initialization()
{
Thread initThread = new Thread(new ThreadStart(InitializationThread));
initThread.Start();
}
public void InitializationThread()
{
outputMessage("Initializing...");
//DO INITIALIZATION
outputMessage("Initialization Complete");
}
I have read a few articles about the BackgroundWorker and how it should allow me to keep my application responsive without ever having to write a thread to perform lengthy tasks but I haven't had any success trying to implement it, could anyone tell how I would do this using the BackgroundWorker?
Add using
using System.ComponentModel;
Declare Background Worker:
private readonly BackgroundWorker worker = new BackgroundWorker();
Subscribe to events:
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
Implement two methods:
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
//update ui once worker complete his work
}
Run worker async whenever your need.
worker.RunWorkerAsync();
Track progress (optional, but often useful)
a) subscribe to ProgressChanged event and use ReportProgress(Int32) in DoWork
b) set worker.WorkerReportsProgress = true; (credits to #zagy)
You may want to also look into using Task instead of background workers.
The easiest way to do this is in your example is Task.Run(InitializationThread);.
There are several benefits to using tasks instead of background workers. For example, the new async/await features in .net 4.5 use Task for threading. Here is some documentation about Task
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task
using System;
using System.ComponentModel;
using System.Threading;
namespace BackGroundWorkerExample
{
class Program
{
private static BackgroundWorker backgroundWorker;
static void Main(string[] args)
{
backgroundWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
backgroundWorker.DoWork += backgroundWorker_DoWork;
//For the display of operation progress to UI.
backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
//After the completation of operation.
backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync("Press Enter in the next 5 seconds to Cancel operation:");
Console.ReadLine();
if (backgroundWorker.IsBusy)
{
backgroundWorker.CancelAsync();
Console.ReadLine();
}
}
static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 200; i++)
{
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
return;
}
backgroundWorker.ReportProgress(i);
Thread.Sleep(1000);
e.Result = 1000;
}
}
static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine("Completed" + e.ProgressPercentage + "%");
}
static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
Console.WriteLine("Operation Cancelled");
}
else if (e.Error != null)
{
Console.WriteLine("Error in Process :" + e.Error);
}
else
{
Console.WriteLine("Operation Completed :" + e.Result);
}
}
}
}
Also, referr the below link you will understand the concepts of Background:
http://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/
I found this (WPF Multithreading: Using the BackgroundWorker and Reporting the Progress to the UI. link) to contain the rest of the details which are missing from #Andrew's answer.
The one thing I found very useful was that the worker thread couldn't access the MainWindow's controls (in it's own method), however when using a delegate inside the main windows event handler it was possible.
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
pd.Close();
// Get a result from the asynchronous worker
T t = (t)args.Result
this.ExampleControl.Text = t.BlaBla;
};