Basically, I have a frequency that refreshes data on screen. When one of these data points goes over a set value, it sets off an error. Upon this error setting off, I want the background colour to change (like a flashing warning).
The problem I have is that I am already using a timer, and when I call a new timer (for the flash) it stops the other timer working, and I'm unaware of how to call in the previous method (being as it uses object sender)
Here is my code:
public void Freq_Change(object sender, SelectionChangedEventArgs e)
{
_timer.Stop();
_timer.Interval = TimeSpan.FromSeconds(Freq.SelectedIndex + 1);
_timer.Start();
_timer.Tick += timer_Tick;
}
and timer_Tick
void timer_Tick(object sender, EventArgs e)
{
//Data generator
//Value pushes to text boxes
if (value is over 100)
{
Warning_Blink
"Oh no, an error"
}
else
{
"All good"
}
Warning_Blink has the new timer in, which then calls warning_Tick
In warning_Tick
private bool _warning = false;
private void warning_Tick(object sender, EventArgs e)
{
if (_warning)
{
ErrorBox.Background = new SolidColorBrush(Colors.Red);
}
else
{
ErrorBox.Background = new SolidColorBrush(Colors.White);
}
_warning = !_warning;
Freq_Change();
}
Here where I call Freq_Change (which doesn't work) I want to be able to go back to the old timer (or better yet never switch between the two) so the data generation can continue.
Can anyone help me with this? I've been scratching my head for hours
Related
I want to make an alarm program where the user is asked to choose the time and the day of the week. If the user choose the day, the text in the label will be in bold. I am having trouble to pass the list from button2_click to Timer_Elapsed. The program worked well except when i pressed the button, the functions in Timer_Elapsed wont work.
List<string> list = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
DateTime currentTime = DateTime.Now;
DateTime userTime = dateTimePicker1.Value;
foreach(string _list in list)
{
if(currentTime.DayOfWeek.Equals(_list) && currentTime.Hour==userTime.Hour && currentTime.Minute==userTime.Minute && currentTime.Second == userTime.Second)
{
SoundPlayer player = new SoundPlayer();
player.SoundLocation = #"C:\Users\Andrew\Music\test1.wav";
player.PlayLooping();
if(MessageBox.Show("","It's Time!", MessageBoxButtons.OK)==DialogResult.OK)
{
player.Stop();
}
}
}
}
private void button2_Click(object sender, EventArgs e)
{
timer.Start();
if (label3.Font.Bold)
{
list.Add("Monday");
}
if (label4.Font.Bold)
{
list.Add("Tuesday");
}
if (label5.Font.Bold)
{
list.Add("Wednesday");
}
if (label6.Font.Bold)
{
list.Add("Thursday");
}
if (label7.Font.Bold)
{
list.Add("Friday");
}
if (label8.Font.Bold)
{
list.Add("Saturday");
}
if (label9.Font.Bold)
{
list.Add("Sunday");
}
foreach (string _list in list)
{
label10.Text = label10.Text + _list + " ";
}
label10.Visible = true;
}
private void label3_Click(object sender, EventArgs e)
{
label3.Font = new Font(label3.Font, FontStyle.Bold);
}
private void label4_Click(object sender, EventArgs e)
{
label4.Font = new Font(label4.Font, FontStyle.Bold);
}
private void label5_Click(object sender, EventArgs e)
{
label5.Font = new Font(label5.Font, FontStyle.Bold);
}
private void label6_Click(object sender, EventArgs e)
{
label6.Font = new Font(label6.Font, FontStyle.Bold);
}
private void label7_Click(object sender, EventArgs e)
{
label7.Font = new Font(label7.Font, FontStyle.Bold);
}
private void label8_Click(object sender, EventArgs e)
{
label8.Font = new Font(label8.Font, FontStyle.Bold);
}
private void label9_Click(object sender, EventArgs e)
{
label9.Font = new Font(label9.Font, FontStyle.Bold);
}
private void button1_Click(object sender, EventArgs e)
{
label3.Font = new Font(label3.Font, FontStyle.Regular);
label4.Font = new Font(label4.Font, FontStyle.Regular);
label5.Font = new Font(label5.Font, FontStyle.Regular);
label6.Font = new Font(label6.Font, FontStyle.Regular);
label7.Font = new Font(label7.Font, FontStyle.Regular);
label8.Font = new Font(label8.Font, FontStyle.Regular);
label9.Font = new Font(label9.Font, FontStyle.Regular);
}
In if statement, You are comparing DayOfWeek Enum value to string: currentTime.DayOfWeek.Equals(_list) this will be always false. Change with this:
currentTime.DayOfWeek.ToString().Equals(_list)
Just like Giorgi said, you are comparing the Enum to a string. You would need to ToString() it before.
As for the rest of your code, here are a couple pointers to make it better overall, since you seem to be beginning. If you don't understand one of the tips, try to read about it. Understanding why it is better is much more important than just blindly changing it. Most of the tips are extremely simplified pointers, and the level is pretty basic too.
Better functionality:
Make a label click either turn it bold or turn it back to normal, depending on it's current state. This will allow a user to remove one of them easily. This will make button1 irrelevant too.
label3.Font = new Font(label3.Font, label3.Font.Bold ? FontStyle.Regular : FontStyle.Bold);
Allow button2 to deactivate the alarm, by clicking it again.
Do not hard-code the path to your sound, instead include it as a ressource, or just put it in the folder with the executable and use a relative path
Nobody needs an alarm up to the second. Make the timer Interval about 30 seconds or so (to avoid millisecond errors), and compare up to the minute.
Don't start the alarm if it is already ringing
Safeguard your dangerous code, like finding the sound file, either by checking it exists beforehand (and reacting appropriately) or with a simple try catch, so that your program doesn't crash at critical moments.
Better code:
Add Enum values (from DayofWeek) to your list, then you will not need to convert anything to compare them
Name your form controls and variables better, so that their use is obvious from the name. "label3", "button2", "list" are horrible names for variables, especially global ones.
Considering the fact that you don't give any other option than "OK" when it rings, don't test the dialog response at all.
player.PlayLooping();
MessageBox.Show("", "It's time!");
player.Stop();
Use the same function for all label clicks, like this:
private void labelDay_Click(object sender, EventArgs e)
{
Label currentLbl = (label) sender;
currentLbl.Font = new Font(currentLbl.Font, currentLbl.Font.Bold ? FontStyle.Regular : FontStyle.Bold);
}
Hold all your labels in an array, so that you can loop through them in the button clicks
Compare the time using a difference, so that you don't have to compare days, then hours, then minutes, etc. A DateTime can easily be compared in one operation.
WinForms has a timer component that you can use from the editor
Dispose of your SoundPlayer when you're done with it, or re-use it. C# takes care of that for you behind the scenes, but that is a very good habit to learn in programming in general
That should be a good start to learning a few very useful things about C# and WinForms, and starting to use better code practices. This is in no way an exhaustive list of everything that could be improved, but since you probably don't plan on ever turning this program into a piece of software used by the whole world, this should be a good stepping stone for you.
i´m doing a winform app, and the timer isn´t working fine. First time works, and then, it doesn´t.
Here is the code:
public void GetNewTurn(Turn turn)
{
_tmrStarTime = DateTime.Now;
timer1.Start();
timer1.Tick += tmr1_Tick;
}
private void tmr1_Tick(object sender, EventArgs e)
{
//timer code here
timer.stop();
}
So, the idea is:
GetNewTurn is a function which is invoked from another place. The first time which I invoke it, works fine, then doesn´t. I put a breakpoint inside the tmr1_Tick, and i can see that it just works the first time, then, doesn´t.
In the Timer properties, i set Enable = True.
What i´m doing wrong?
Thanks!
You shoudn't stop the tmr1_Tick in the first tick
public void GetNewTurn(Turn turn)
{
_tmrStarTime = DateTime.Now;
timer1.Start();
timer1.Tick += tmr1_Tick;
}
private void tmr1_Tick(object sender, EventArgs e)
{
//the code for each tick
}
Only add the handler once in the constructor or OnLoad override.
timer1.Tick += tmr1_Tick;
public void GetNewTurn(Turn turn)
{
_tmrStarTime = DateTime.Now;
timer1.Start();
}
I have a tabbed form with a StatusStrip at the bottom, which includes a StatusLabel. I want to use this status label for various actions ("1 record updated" etc). It is simple enough to create specific events to set the label's text property.
But how best to reset the status to blank? The user could perform any number of other operations where the status is no longer meaningful (going to another tab, clicking other buttons etc.).
It is not feasible to create all the possible events to reset the status message. Is there a way to incorporate some type of timer so that the message fades out after several seconds? Has anyone else found a good solution for this?
Is it truly important to clear the status though? There are plenty of products which will keep their status label unchanged until the next status event occurs. Visual Studio is a good example of this. It may be worth simplifying your scenario and taking this approach.
If you do want to clear the status after an event I think the most maintainable way to do this is with a Timer. Essentially clear after a few seconds when the status is set
Timer m_timer;
void SetStatus(string text) {
m_statusLabel.Text = text;
m_timer.Reset();
}
void OnTimerTick(object sender, EventArgs e) {
m_statusLabel.Text = "";
m_timer.Stop();
}
Yes a timer would work for this to clear it. Here is an example of one I've knocked together.
public partial class Form1 : Form
{
private System.Timers.Timer _systemTimer = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_systemTimer = new System.Timers.Timer(500);
_systemTimer.Elapsed += _systemTimer_Elapsed;
}
void _systemTimer_Elapsed(object sender, ElapsedEventArgs e)
{
toolStripStatusLabel1.Text = string.Empty;
_systemTimer.Stop(); // stop it if you don't want it repeating
}
private void button1_Click(object sender, EventArgs e)
{
toolStripStatusLabel1.Text = "random text just as an example";
}
private void button2_Click(object sender, EventArgs e)
{
_systemTimer.Start();
}
}
Assume button1 is your action to update the status, and button2 is just a random way to start the timer (this can be however you want to start it, I've only used another button click as an example). After the set amount of time passes the status label will be cleared.
I have an unusual thing happening with an RSS presenter I'm trying to make. It's meant to go to the next item after an 'Out' animation is played, then play the 'In' animation. http://oeis.org/A000217
void _timer_Tick(object sender, EventArgs e)
{
Storyboard sbOut = this.FindResource("sbAnimateOut") as Storyboard;
sbOut.Completed += new EventHandler(sbOut_Completed);
sbOut.Begin();
}
void sbOut_Completed(object sender, EventArgs e)
{
if (_selected < _total)
{
_selected++;
}
else
{
GetFeed(_feed);
_selected = 0;
}
lstbxItems.SelectedIndex = _selected;
counter.Text = _selected.ToString();
Storyboard sbIn = this.FindResource("sbAnimateIn") as Storyboard;
sbIn.Begin();
}
I noticed it seem to skip items though. When I step through it line by line, it seems to execute the void sbOut_Completed(object sender, EventArgs e) once the first time, three times the second time, six times the third time - and so on, sequentially.
Perhaps I'm going about this the wrong way and that's causing the issue? Any suggestions?
You are adding another event handler every timer tick!
Move this code:
sbOut.Completed += new EventHandler(sbOut_Completed);
into your initialization - only do it once.
Consider following situation:
there is ComboBox and a filter TextBox, then user types a text in a text box ComboBox items source is updated using filter text. Everything works, but filtering occurs on every typed letter. I want to add a delay before filtering occurs (filter is not applyed while user is typing). What is the simpliest way to do it?
The most used way of doing this is introducing a timer where everytime the user enters a new character your timespan get's reset but if it is longer than x seconds then execute the code.
Remember to do it async so that if the user starts typing again while you are performing a search you can cancel the async call as that information will now be outdated.
If you are using a viewmodel just change textbox1_TextChanged to the appropriate Properties setter
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
if (!tmr.Enabled)
{
tmr.Enabled = true;
tmr.Start();
}
TimeSinceType = DateTime.Now;
}
public DateTime TimeSinceType { get; set; }
protected void Load()
{
tmr = new Timer();
tmr.Interval = 200;
tmr.Elapsed += new ElapsedEventHandler(tmr_Elapsed);
}
void tmr_Elapsed(object sender, ElapsedEventArgs e)
{
if ((DateTime.Now - TimeSinceType).Seconds > .5)
{
Dispatcher.BeginInvoke((Action)delegate()
{
//LoadData();
tmr.Stop();
});
}
}
This can be done much easier now by putting a delay directly on the binding:
<ComboBox Text={Binding MyBinding, Delay=200} />