i can run timer but it is hanging , when i run background i need timer to be run in background.
can anyone say me how to run timer in background.
My timer code is
btnIntraday.Enabled = false;
btnStartBackfill.Enabled = false;
btnStop.Enabled = true;
if (btnIntraday.Text == "Intraday")
{
timerIntraday.Interval = 5000;
timerIntraday.Enabled = true;
btnIntraday.Text = "Updating..";
}
else if (btnIntraday.Text == "Updating..")
{
timerIntraday.Enabled = false;
btnIntraday.Text = "Intraday";
}
and my background code is
btnIntraday.Enabled = false;
btnStartBackfill.Enabled = false;
btnStop.Enabled = true;
txtInterval.Text = ddTimeInterval.Value.ToString();
int inter = (int.Parse(txtInterval.Text)) * multiplyingFactorBackfill;
try
{
bgBackfillDCX.RunWorkerAsync();
}
catch (Exception ex)
{
}
can anyone please say me how to run timer in background.
Thanks in advance.
You may use a BackgroundWorker.
Handle the BackgroundWorker.DoWork to run your timer.
Handle the BackgroundWorker.ProgressChanged to handle timing events.
Handle the BackgroundWorker.RunWorkerCompleted to stop the timer.
I think what you are saying is that you want to set off the background code then have IT periodically do some work. If so you need a timer in the background code not the front end. Which means using a different timer class - in System.Timers, IIRC. System.Timers.Timer
If You insist on having the timer working at the front end (though I don't recommend it, I can understand it is easier in some scenarios), there is a way (note: I presume Windows Forms are used):
In the following code, there is:
a timer referring to an instance of System.Windows.Forms.Timer object
a notifyIcon referring to an instance System.Windows.Forms.NotifyIcon object
MainWindow_Resize method associated with Resize event of the form
notifyIcon_Click method associated with Click event of the notifyIcon
The resize method if-block is executed when user minimizes form (form is not visible anywhere in desktop and setting ShowInTaskBar to false hides it from task bar as well, so it is effectively hidden).
private void MainWindow_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
this.ShowInTaskbar = false;
notifyIcon.Visible = true;
}
}
When user clicks notification icon, the form's window is restored to its former size and position and the form is brought to user
private void notifyIcon_Click(object sender, EventArgs e)
{
notifyIcon.Visible = false;
this.WindowState = FormWindowState.Normal;
this.ShowInTaskbar = true;
this.BringToFront();
this.Activate();
}
Related
This question already has answers here:
How to stop BackgroundWorker on Form's Closing event?
(12 answers)
Closed 6 years ago.
The whole program freeze and gray like enabled false i can't click on it do nothing only close it from the visual studio Stop Debugging.
It started once after i added: protected override void OnFormClosing
bool mCompleted = false;
bool mClosePending = false;
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (!mCompleted)
{
backgroundWorker1.CancelAsync();
this.Enabled = false;
e.Cancel = true;
mClosePending = true;
return;
}
base.OnFormClosing(e);
}
I added this override since i wanted to make sure the backgroundworker i'm using was stop before closing the form1 when i click the right top x. So it is working while the backgroundworker is running but when the backgroundworker is not running i just run the program and click the x then the whole program is like enabled false and all i can do is shut it down by stop debugging.
In backgroundworker completed event i did:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
}
if (e.Error != null)
{
}
else
{
mCompleted = true;
if (mClosePending) this.Close();
}
}
But the problem happen when the backgroundworker is not running and i just click the x.
If your flag mCompleted is false in the OnClosing override you enter the first if condition without checking if your background worker is running or not. This disables the main form (this.Enabled = false;) and cancels the closing (e.Cancel = true;) even if the background worker is not running. At this point there is no code that closes the form because obviously the WorkerCompleted event is not raised on a not running BackgroundWorker.
You need to check the IsBusy property.
if (!mCompleted && backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
this.Enabled = false;
e.Cancel = true;
mClosePending = true;
return;
}
base.OnFormClosing(e);
By setting Cancel to true you are effectively aborting the form closing and leaving it disabled:
this.Enabled = false;
e.Cancel = true;
You should add a check to make sure the BackgroundWorker is running so it will eventually close the form.
You might also want to add a timeout in case the worker get stuck in some cases depending on your worker's job.
Ideally you would use a wait event to wait for the worker to finish and then close the form rather than relying on the worker to close it so you can keep the closing logic in one place.
Have a look at this answer: How to wait for BackgroundWorker to finish and then exit console application
I think that use with flag is most simple.
The flag will update in:
ProgressChanged(object sender, ProgressChangedEventArgs e)
or in the Timer option.
I have created a Windows Forms Console Application in which I am reading a file which has been written by another console application.
The other console application will write about the status of some process and the Windows Forms application will read the status and accordingly update the status text box.
I wrote the following code for above scenario.
while (true)
{
if ((new FileInfo(filename)).Length > 0)
{
Status = File.ReadAllText(filename, Encoding.ASCII);
System.IO.File.WriteAllText(filename, string.Empty);
Statustb.Text = Status;
Statustb.Refresh();
if (Status.Equals("Data Got Loaded"))
{
Environment.Exit(0);
}
}
}
When I am running the Windows Forms application it shows "Form Not Responding" but when I comment out these lines then it will run smoothly. But for me it is important to update the status.
You have to understand the architecture of a GUI application.
All interactions with the user happen on one thread.
This includes reacting to things like mouse and keyboard events etc.
If one of these events happens you can handle that event and do something in response to it.
But, until you return from the handler, the application will not be able to receive any further notifications (Windows Messages aka events).
I suspect you have the above code in either the constructor or in one or other event handler. Since you never exit (infinite loop, due to while(true) without a return or break, the operating system cannot send any further events to the application. They get put in a queue to be sent, but never get picked up.
Windows will detect this situation and give you the Not Responding dialog message.
I suggest, that, instead of having the code inside the while(true) loop, you create a Timer with a suitable Interval, and put the body of the while statement (ie the bit between the { and }, but not the while(true) itself ) in the Tick handler.
It is better to use the code inside a timer.
Still, you need to make sure that no two different threads at the same time accessing a file. You should have used lock while reading and writing it.
I have a pattern that I use for getting long running tasks off of the UI thread. To see it, create a Winforms project and open the code-behind for Form1.cs. Delete the content and copy the following into that file. It should run and it has comments describing what it is doing.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace POC_DoEvents_alternate
{
public partial class Form1 : Form
{
private Button button1;
private Button button2;
private TextBox textbox1;
public Form1()
{
InitializeComponent();
// programmatically create the controls so that the
// entire source code is contained in this file.
// normally you wouldn't do this.
button1 = new Button();
button1.Name = "button1";
button1.Enabled = true;
button1.Location = new Point(12, 12);
button1.Size = new Size(144, 35);
button1.Text = "button1";
button1.Click += button1_Click;
this.Controls.Add(button1);
button2 = new Button();
button2.Name = "button2";
button2.Enabled = false;
button2.Location = new Point(12, 53);
button2.Size = new Size(144, 35);
button2.Text = "button2";
button2.Click += button2_Click;
this.Controls.Add(button2);
textbox1 = new TextBox();
textbox1.Name = "textbox1";
textbox1.Location = new Point(12, 94);
textbox1.ReadOnly = true;
textbox1.Size = new Size(258, 22);
this.Controls.Add(textbox1);
this.Load += new System.EventHandler(this.Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
textbox1.Text = "You can't press button 2 yet...";
button1.Enabled = true;
button2.Enabled = false;
this.Cursor = Cursors.AppStarting;
// start the long running task in a separate background thread
ThreadPool.QueueUserWorkItem(Async_LongRunningTask, "Form1_Load");
// calling the QueueUserWorkItem will not block. Execution will
// contiune immediately with the lines below it.
textbox1.BackColor = Color.LightPink;
// this event handler finishes quickly so the form will paint and
// be responsive to the user.
}
private void button1_Click(object sender, EventArgs e)
{
textbox1.Text = "Button 1 pressed";
}
private void button2_Click(object sender, EventArgs e)
{
textbox1.Text = "Button 2 pressed";
}
private void Async_LongRunningTask(object state)
{
// put all your long running code here, just don't put any
// UI work on this thread
Thread.Sleep(5000); // simulates a long running task
// put any UI control work back on the UI thread
this.Invoke((MethodInvoker)delegate
{
button2.Enabled = true;
textbox1.Text = "End of long running task: " + state.ToString();
textbox1.BackColor = SystemColors.Control;
this.Cursor = Cursors.Default;
// as with anything on the UI thread, this delegate
// should end quickly
});
// once the delegate is submitted to the UI thread
// this thread can still do more work, but being a
// background thread, it will stop when the application
// stops.
Thread.Sleep(2000); // simulates a long running task
}
}
}
You can add using System.Windows.Forms;
Application.DoEvents();
in the While
I already tried google to find an answer to my problem but haven't found a solution.
I working with C# and WinForms. I created a panel and added a label to it. This panel is set to myPanel.Visible = falseat first. I want to set it myPanel.Visible = true when I click a button. The button is calling a function. During the function call I want to show a progessbar in the panel, so I set this myPanel.Visible = trueand at the end of the function I set it back to myPanel.Visible = false.
The problem is, that the label isn't visible.
When I don't set myPanel.Visible = false at the end of the function, the label is visible, but only at the end of the function.
I also tried to programmatically add the label in the function called, still not working. The second idea I tried was to use this.PerformLayout(); during the call of the function.
It seems like that the application is drawing the label only at the end of the function call, but I need it to be drawn during the function is called.
Thanks for any help.
private void buttonAdd_Click(object sender, EventArgs e)
{
//Adding label to panel
MyLabel label = new MyLabel();
label.Text = "Test";
label.Location = new Point(0, 0);
progressPanel.Controls.Add(label);
//Showing progressPanel
progressPanel.Visible = true;
progressBar1.Minimum = 1;
progressBar1.Value = 1;
progressBar1.Step = 1;
//Some Code
progressPanel.Visible = false;
}
Your problem is obviously that you are performing your task in the UI thread. So the UI itself doesn't get repainted while this task is working. And when you finished, it's still invisible.
Try using a BackgroundWorker instead. Use its ProgressChanged event to update your progress bar.
If you show some code, I can go into details of implementation.
UPDATE:
I actually prefer sstan's answer, but I promised to show the BackgroundWorker way. It may still be helpful if for some reason you cannot use async/await:
public partial class Form1 : Form
{
private BackgroundWorker _backgroundWorker;
public Form1()
{
InitializeComponent();
_backgroundWorker.DoWork += DoWork;
_backgroundWorker.RunWorkerCompleted += WorkerCompleted;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.ProgressChanged += WorkerProgressed;
}
private void buttonAdd_Click(object sender, EventArgs e)
{
//Adding label to panel
MyLabel label = new MyLabel();
label.Text = "Test";
label.Location = new Point(0, 0);
progressPanel.Controls.Add(label);
//Showing progressPanel
progressPanel.Visible = true;
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
progressBar1.Value = 0;
progressBar1.Step = 1;
// to avoid multiple starts
buttonAdd.Enabled = false;
// start working
_backgroundWorker.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
_backgroundWorker.ReportProgress(1);
// work
_backgroundWorker.ReportProgress(50);
// more work
_backgroundWorker.ReportProgress(100);
}
private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressPanel.Visible = false;
buttonAdd.Enabled = true;
}
private void WorkerProgress(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
}
So as you see, BackgroundWorkers are fairly easy to use, but async/await is even easier since you don't have to write so much code just for parallelization.
The behavior you see is normal. The changes in visibility only take effect when the UI thread gets a chance to repaint your window. But, while you function is running, the UI thread is busy, so it can't repaint your window. The UI thread only frees up at the end of your function call, so that's when the component's visibility changes take effect.
What you need to do is to perform your function's work on a different thread so that the UI thread is free to repaint your window while the function is still running.
One way to do this, is by using Task.Run() combined with the async/await keywords. Here is a basic example of how this could look like, using the code you posted:
async private void buttonAdd_Click(object sender, EventArgs e)
{
// ....
//Showing progressPanel
progressPanel.Visible = true;
progressBar1.Minimum = 1;
progressBar1.Value = 1;
progressBar1.Step = 1;
// this work will happen on separate thread,
// so the UI thread will be free to update the panel visibility
Progress<int> progress = new Progress<int>(percentage => progressBar1.Value = percentage);
await Task.Run(() => this.WorkToBePerformedOnSeparateThread(progress));
progressPanel.Visible = false;
}
private void WorkToBePerformedOnSeparateThread(IProgress<int> progress)
{
// do work...
progress.Report(25); // Report 25% completed...
// do more work
progress.Report(50); // Report 50% completed...
// more work
progress.Report(75); // Report 75% completed...
// etc...
}
As pointed out by Rene in the comments, just remember that you can only do UI work on the UI thread. So, in the example above, you'll notice that the progress reporting is performed through the Progress<T> class which allows you to change the progress bar value (UI work) from the separate thread, because it takes care of ensuring that the progress reporting happens on the UI thread.
I'm having some issues while waiting for a ThreadState during the Click event of a button control.
Whenever I click my button it'll execute the code below.
The problem with this is that it won't wait until the ThreadState is "Stopped", so it never enables btnImportData or btnExportBellijst.
I've tried t.Join() but that freezes my whole form and I use a RichTextBox as logger, so that'd result in a logger that freezes for a few seconds and then shows a lot of text at once.
The reason I put the ImportData function on another Thread is to keep the form running so people can see the logs happening realtime.
What I'd like to have when I click my button:
Change Enabled of 1 or more buttons.
Run my function ImportData on another thread so my logger can keep logging. (void ImportData(){})
Change Enabled of 1 or more buttons after my function is done doing something.
private void btnImportData_Click(object sender, EventArgs e)
{
//Disable current button
btnImportData.Enabled = false;
imgBonne.Visible = false; //random image
rtConsole.Visible = true; //RichTextBox logger
//Create a new thread for the button function
var t = new Thread(ImportData);
t.Start();
//It does NOT wait until thread stopped
while (t.ThreadState == ThreadState.Stopped)
{
//Never gets executed
btnImportData.Enabled = true;
btnExportBellijst.Enabled = true;
}
}
Extra Info: Screenshot from before pressing "Import Data": http://puu.sh/88oD6.png
Screenshot from after the application is done importing data: http://puu.sh/88oNT.png
(edit)Target framework: .NET Framework 4
I was originally using the code below, but this instantly enables all the buttons after pressing "Import Data".
private void btnImportData_Click(object sender, EventArgs e)
{
imgBonne.Visible = false; //random image
rtConsole.Visible = true; //RichTextBox logger
var t = new Thread(ImportData);
t.Start();
while (t.ThreadState == ThreadState.Running)
{
btnImportData.Enabled = false;
}
btnImportData.Enabled = true;
btnExportBellijst.Enabled = true;
}
Edit: I'm sorry if this is in the wrong category, I wanted to put it in c#.
Using the Task Parallel Library can make it a whole lot easier:
private void btnImportData_Click(object sender, EventArgs e)
{
imgBonne.Visible = false; //random image
rtConsole.Visible = true; //RichTextBox logger
btnImportData.Enabled = false;
Task.Run(ImportData).ContinueWith((Task task) =>
{
btnImportData.Enabled = true;
btnExportBellijst.Enabled = true;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
Does anyone know how I can change the window state of a form, from another thread? This is the code I'm using:
private void button4_Click(object sender, EventArgs e)
{
string pathe = label1.Text;
string name = Path.GetFileName(pathe);
pathe = pathe.Replace(name, "");
string runpath = label2.Text;
Process process;
process = new Process();
process.EnableRaisingEvents = true;
process.Exited += new System.EventHandler(process_Exited);
process.StartInfo.FileName = #runpath;
process.StartInfo.WorkingDirectory = #pathe;
process.Start();
WindowState = FormWindowState.Minimized;
}
private void process_Exited(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Normal;
}
It's meant to run a program and minimize, then return to the normal state once the program has closed. Although I get this error "Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on." Any idea how to get this to work?
This will work in .NET 3.5:
Invoke(new Action(() => { this.WindowState = FormWindowState.Normal; }));
Or 2.0:
Invoke(new MethodInvoker(delegate { this.WindowState = FormWindowState.Normal; }));
Just search this string in StackOverflow "Cross-thread operation not valid" or Google. Please, don't be that lazy.
See What’s the difference between Invoke() and BeginInvoke() on this site. The "chosen" answer gives a good explanation of what you're supposed to do.
Long story short, you want different THREADS not making a new process entirely (or highly unlikely you want that), and you probably want to use Invoke() and not BeginInvoke() which is asynchronous.
Add this line of code to the Click event handler:
process.SynchronizingObject = this;
this will solve your problem add it in the form_load event
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;