How to setStatus after timer.Elapsed - c#

My question is probably quite simple. In a c# project i am trying to set a status of an instance in a different class at a click event. The trouble is that i want to do this after a certain time has elapsed and without any c# experience I find this quite hard to accomplish.
Thanks in advance!!
my code is as follows:
public void button1_Click(object sender, EventArgs e)
{
kruispunt.zPad1.voetstoplicht1.setStatus(StoplichtStatus.Rood);
kruispunt.zPad1.voetstoplicht2.setStatus(StoplichtStatus.Rood);
this.Refresh();
}

The easiest way is to use async (assuming you're using C# 5):
public async void button1_Click(object sender, EventArgs e)
{
await Task.Delay(Timespan.FromSeconds(5));
kruispunt.zPad1.voetstoplicht1.setStatus(StoplichtStatus.Rood);
kruispunt.zPad1.voetstoplicht2.setStatus(StoplichtStatus.Rood);
this.Refresh();
}
Another option is to use a Timer:
public void button1_Click(object sender, EventArgs e)
{
var timer = new System.Windows.Forms.Timer { Interval = 5000 };
timer.Tick += delegate
{
timer.Dispose();
kruispunt.zPad1.voetstoplicht1.setStatus(StoplichtStatus.Rood);
kruispunt.zPad1.voetstoplicht2.setStatus(StoplichtStatus.Rood);
this.Refresh();
}
timer.Start();
}
Note that I used a Windows Forms timer, rather than System.Timers.Timer or System.Threading.Timer; this is because the event must occur in the UI thread, otherwise the call to Refresh would fail.

Related

Timer to refresh charts in c#

I have created a chart which receives its data from a SQL Server database. Whenever I save new data into the database, all the reports get updated, but the chart does not update until I exit the application and log in again. I decided to use Timer in C# to automatically refresh the chart every 5 seconds.
//this is to invoke the timer as soon as the application launches.
public MDIParent2()
{
InitializeComponent();
myTimer.Enabled = true;
myTimer.Start();
}
//this is my timer event
private void myTimer_Tick(object sender, EventArgs e)
{
this.Refresh();
MessageBox.Show("Refreshed!");//this was added to determine if the timer is working
}
//this lets me stop the timer
private void button1_Click(object sender, EventArgs e)
{
myTimer.Stop();
}
//this lets me resume the timer
private void button2_Click(object sender, EventArgs e)
{
myTimer.Start();
}
I get the message "Refreshed!" every 5 seconds, but chart is still not refreshed. Can someone please assist?
replace this.refresh() with [Chart Object].refresh()

C# show timer in textbox

I'm trying to make a timer run in a textbox and I haven't had any luck.
This is the code I'm using:
private static System.Timers.Timer timer;
...
private void StartBtn_Click(object sender, EventArgs e)
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Enabled = true;
}
...
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
TimeTb.Text = e.SignalTime.ToString();
}
But nothing happens.
I tried this:
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
MessageBox.Show(e.SignalTime.ToString(),
"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}
And it worked fine. Anyone know why it isn't working with my textbox?
The Elapsed Event runs on a different Thread then the UI. Its not allowed to manipulate UI Objects from a different thread and an Exception should surface in your EventHandler. Since you don't handle Exceptions there you won't notice it.
In StartBtn_Click set the SynchronizingObject Property of the Timer to this (the form). Then the elapsed Event will be synchronized with the main thread.
May be you should start the timer first.
Take a look at:
http://msdn.microsoft.com/en-us/library/system.timers.timer.start.aspx
So add:
timer.Start();
Put a try catch around OnTimedEvent and see if there are any issues with threading.
If there are, try using the System.Windows.Forms.Timer which can resolve the issues of cross threading.
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx
As stated:
Implements a timer that raises an event at user-defined intervals.
This timer is optimized for use in Windows Forms applications and must
be used in a window.
Your OnTimedEvent callback will not be called on the UI thread, so you will get an exception in there trying to set the textbox text. So you need to change the event handler to look like this:
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (TimeTb.InvokeRequired)
{
TimeTb.Invoke((MethodInvoker)delegate
{
OnTimedEvent(source, e);
});
}
TimeTb.Text = e.SignalTime.ToString();
}
Maybe using Application.DoEvents(); after TimeTb.Text = e.SignalTime.ToString(); would work, though using it would not be recommended (Use of Application.DoEvents()).
you could do something like
private void Button_Click(object sender, RoutedEventArgs e)
{
this._timer = new DispatcherTimer();
this._timer.Interval = TimeSpan.FromMilliseconds(1);
this._timer.Tick += new EventHandler(_timer_Tick);
_timer.Start();
}
void _timer_Tick(object sender, EventArgs e)
{
t= t.Add(TimeSpan.FromMilliseconds(1));
textBox.Text = t.Hours + ":" + t.Minutes + ":" + t.Seconds + ":" + t.Milliseconds;
}
Edit :
How to add Assembly: WindowsBase

C# Threading, 1st Task DoSomething, 2nd Task update a WinFormLabel (Realtime)?

Lets say I have Task 1:
private void Task1()
{
//Here is some Code, could be any "longer" Task -
//For Example: Grab all words from a .txt File and fill in a List<String>
}
Then I have an other Task 2:
private void Task2(string word)
{
//So lets say theres a Label on my WinForm..
//Now While Task1 is grabbing the words, Task2 should fill a Label
//with the added 'word' (parameter) - (Task2 will be called from Task1
}
Actually I don't know how to make this possible, or whats the best way. On the UI I should be able to see the Label.Text changing (every word).. So I need to make a second Thread? How could I do this? Maybe someone could help me, cheers
UPDATE:
I tried it now with the Backgroundworker, but something seems to be false.. its actually not working, nothing happens on the form
Code:
public void CreateAndSaveAMatch(DateTime date) //That method is being called several times
{
//HERE IS CODE, WHICH CREATES AND SAVES A MATCH
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(date);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker1.ReportProgress(0, Convert.ToDateTime(e.Argument).ToShortDateString());
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = (string)e.UserState; //here on the Label I would like to show the Date
}
Ok, try this. This is a simple example that will show you how to solve your problem using BackgroundWorker. Also note that there are many other solutions. To use this example create a Form in a new project that only has a button and a label. Also note that this is a supplement of the other answers which were correct.
public partial class Form1 : Form
{
BackgroundWorker createAndSaveAMatchBGW;
public Form1()
{
InitializeComponent();
createAndSaveAMatchBGW = new BackgroundWorker();
createAndSaveAMatchBGW.DoWork += new DoWorkEventHandler(createAndSaveAMatchBGW_DoWork);
createAndSaveAMatchBGW.ProgressChanged += new ProgressChangedEventHandler(createAndSaveAMatchBGW_ProgressChanged);
createAndSaveAMatchBGW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createAndSaveAMatchBGW_RunWorkerCompleted);
createAndSaveAMatchBGW.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
createAndSaveAMatchBGW.RunWorkerAsync(DateTime.Now);
}
void createAndSaveAMatchBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("BackgroundWorker finished");
}
void createAndSaveAMatchBGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = ((DateTime)e.UserState).ToString("ss");
}
void createAndSaveAMatchBGW_DoWork(object sender, DoWorkEventArgs e)
{
//BackgroundWorker does something for a 10 seconds, each second it Reports
BackgroundWorker bgw = (BackgroundWorker)sender;
DateTime dt = (DateTime) e.Argument;
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
dt = dt.AddSeconds(1);
bgw.ReportProgress(0, dt);
}
}
}
And if you report from CreateAndSave... method only once per its execution, then you can use this code:
BackgroundWorker createAndSaveAMatchBGW;
public Form1()
{
InitializeComponent();
createAndSaveAMatchBGW = new BackgroundWorker();
createAndSaveAMatchBGW.DoWork += new DoWorkEventHandler(createAndSaveAMatchBGW_DoWork);
createAndSaveAMatchBGW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createAndSaveAMatchBGW_RunWorkerCompleted);
}
private void button1_Click(object sender, EventArgs e)
{
createAndSaveAMatchBGW.RunWorkerAsync(DateTime.Now);
}
void createAndSaveAMatchBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label1.Text = ((DateTime)e.Result).ToString();
}
void createAndSaveAMatchBGW_DoWork(object sender, DoWorkEventArgs e)
{
DateTime dt = (DateTime) e.Argument;
//you do something with your DateTime
dt = dt.AddDays(10);
e.Result = dt;
}
Use BackgroundWorker for reporting progress from first task. Drag this component from toolbox to your form, and subscribe to DoWork and ProgressChanged events. Also set property WorkerReportsProgress to true. Then start you first task asynchronously:
// this will execute code in `DoWork` event handler
backgroundWorker1.RunWorkerAsync();
Next - use userState object to pass processed words:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// grab words in a loop and report progress
backgroundWorker1.ReportProgress(0, word);
}
And last step - update label in ProgressChanged event handler
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text += (string)e.UserState; // this is your grabbed word
}
The simplest way to achieve this kind of thing is using BackgroundWorker.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
BackgroundWorker automatically handles thread marshalling and provides events that allow you to update the UI. The event handlers run on the UI thread.
The things you do in Task1 could be moved into a BackgroundWorker, and the updates to the UI that you propose to do in Task2 can actually be in response to progress events from BackgroundWorker.
ProgressChangedEventArgs provides for user-defined data that could hold the current word.
However, Winforms (and indeed pretty much any UI) will not be able to keep up with a separate CPU thread just loading words from a file if you intend to show every word you load.
Task1 could be started on a separate thread.
You wouldn't actually need a Task2 unless there was some complex logic being performed to update the TextBox. You you really need to do is use TextBox.Invoke() to invoke the update on the UI Thread from Task1.

Why doesn't System.Timers.Timer update non-busy UI?

I have been looking for a reason, but about every single topic on stackoverflow I could find suggested a busy UI as the reason.
I have very basic code, just for testings and it simply won't update the UI, even though I am sure it cannot be busy doing something else:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
static double t = 0;
static double dt = 0.1;
private void button1_Click(object sender, RoutedEventArgs e)
{
Timer timer = new Timer(5000);
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(Update);
timer.Start();
}
void Update(object sender, ElapsedEventArgs e)
{
t = t + dt;
testBlock1.Text = (t).ToString();
}
}
I debugged it and set a breakpoint to the textBlock1.Text update and it did break every 5 seconds, but the UI is never updated. As can be seen in the code, when I move my mouse over the Button I use to start the timer, the button shows its typical "mouse-over-button" animation. Why does that happen, but not the text update?
If anyone can lead me to a good topic on stackoverflow, please do so and I will delete my question here, but I couldn't find any topic explaining why this approach doesn't update the UI even though the UI is not busy doing anyting else.
System.Timers.Timer won't by default marshal back to the UI thread. In Windows Forms you can make it do so easily enough:
Timer timer = new Timer(5000);
timer.SynchronizingObject = this;
... but WPF UI elements don't implement ISynchronizeInvoke, which would stop this from working for you in WPF.
You could use the Dispatcher to marshal over to the UI thread within the handler, or you could just use a DispatcherTimer to start with.
For WPF, you should use DispatcherTimer -
Also with the above code you posted, i am getting a cross thread error since elapsed event is raised on other thread and not on UI thread.
private void button1_Click(object sender, RoutedEventArgs e)
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 5);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
t = t + dt;
txt.Text = (t + dt).ToString();
}
EDIT
Also, you can marshal it on UI Dispatcher with your existing code like this -
void Update(object sender, ElapsedEventArgs e)
{
App.Current.Dispatcher.Invoke((Action)delegate()
{
t = t + dt;
txt.Text = (t + dt).ToString();
});
}

How to let System.Windows.Forms.Timer to run the Tick handler immediately when starting?

The Timer following is System.Windows.Forms.Timer
C# Code:
Timer myTimer = new Timer();
myTimer.Interval = 10000;
myTimer.Tick += new EventHandler(doSth);
myTimer.Start();
The timer will doSth every 10 seconds, but how to let it doSth immediately when starting?
I tried to create a custom timer which extends Timer, but I can't override the Start method.
For now, my code is:
myTimer.Start();
doSth(this, null);
I don't think it's good. How to improve it?
It's perfect. Don't change a thing.
I'm not sure of your exact requirements but why not put the code inside your timer callback inside another method?
e.g.
private void tmrOneSec_Tick(object sender, System.EventArgs e)
{
DoTimerStuff();
}
private void DoTimerStuff()
{
//put the code that was in your timer callback here
}
So that way you can just call DoTimerStuff() when your application starts up.
The timer has to have form level scope, and it's not clear that you have that. I whipped up a small example out of curiosity and it is working for me:
private void Form1_Load(object sender, EventArgs e)
{
txtLookup.Text = "test";
DoSomething();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
DoSomething();
}
private void DoSomething()
{
txtLookup.Text += "ticking";
}
Every 10 seconds it appends another "ticking" to the text in the textbox.
You say,
"The timer will doSth every 10 seconds, but how to let it doSth immediately when starting?"
I say, call doSth immediately before calling the timer's start method

Categories