Currently, I start looping upon PreviewMouseDown and I was thinking to break the loop using PreviewMouseUp but apparently failed. Below is the way I did it.
public bool stopFlag = true;
public int abc = 0;
private void TestingDown(){
while(stopFlag)
{
abc++;
}
}
private void TestingUp()
{
stopFlag = false;
Message.show(abc);
}
Actually my idea is to create sort of button holding effect, something like smartphone, hold a button for 3 seconds and do something. But there isnt any onHold event for button?
Start the Timer in PreviewMouseDown and check elapsed time in PreviewMouseUp.
In this case your loop runs in the same thread as the whole UI. But actually what you need is to calculate the time between MouseDown and MouseUp events.
DateTime holdStartTime;
public MainWindow()
{
InitializeComponent();
PreviewMouseDown += new MouseButtonEventHandler(MainWindow_PreviewMouseDown);
PreviewMouseUp += new MouseButtonEventHandler(MainWindow_PreviewMouseUp);
}
void MainWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
holdStartTime = DateTime.Now;
}
void MainWindow_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if ((DateTime.Now - holdStartTime).TotalMilliseconds < 1000)
{
Console.WriteLine("Do something");
}
else
{
Console.WriteLine("Do something else");
}
}
I think you need backgroud thread for this as UI thread is busy in this loop.
You can refer below link for more info.
[Background Worker]
Related
I have a little problem. There is something like chess timer. When i press button, current timer stops and second starts, but after 1 second. How can i start second one immediately?
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1 {
public partial class Form1 : Form {
byte sec1;
byte sec2;
public Form1() {
InitializeComponent();
sec1 = 0;
sec2 = 0;
}
private void button1_Click(object sender , EventArgs e) {
timer1.Start();
timer2.Stop();
}
private void button2_Click(object sender , EventArgs e) {
timer2.Start();
timer1.Stop();
}
private void timer1_Tick(object sender , EventArgs e) {
label1.Text = sec1.ToString();
sec1++;
}
private void timer2_Tick(object sender , EventArgs e) {
label2.Text = sec2.ToString();
sec2++;
}
}
}
Edit
I know your question is "how to start the timers immediately", but in your code they are starting immediately. When you call start the timer starts. I believe the effect you are seeing is related to the delay associated with the tick event, which from the description I am assuming is set to a 1 second interval. Since you have said that you are trying to simulate something similar to a chess timer (although in your case counting up as opposed to down), then using something like a stop watch which can start, stop and show elapsed time would be a closer model. Since there is a Stopwatch class that provides exactly this behavior, I think it would be easier to implement it using two of those and just have a single background thread that updates the UI as frequently as needed. You could even add an update call into each button push to ensure the text boxes are up to date.
===============================
Maybe instead of the timers you should use two instances of the Stopwatch class. This will remove the need for your two variables that you are using to keep track of the seconds as the Stopwatch class will be holding the elapsed time for each counter.
Then in your button methods you could just do this:
private Stopwatch sw1 = new Stopwatch();
private Stopwatch sw2 = new Stopwatch();
private void button1_Click(object sender , EventArgs e) {
sw1.Start();
sw2.Stop();
}
private void button2_Click(object sender , EventArgs e) {
sw2.Start();
sw1.Stop();
}
And then you can use a Background worker or some other background thread that runs and updates your text boxes with the elapsed time from the timers you just need to grab the elapsed time.
// This will give you the total number of seconds elapsed.
var timer1Seconds = Math.Floor(sw1.Elapsed.TotalSeconds);
Here is an example of how you can make this update the UI:
private bool _stop = false;
public Form1()
{
InitializeComponent();
Task.Run(() =>
{
while(!_stop)
{
UpdateElapsedTimes();
Thread.Sleep(1000);
}
}
}
private void UpdateElapsedTimes()
{
if (InvokeRequired)
{
Invoke(UpdateElapsedTimes());
return;
}
label1.Text = Math.Floor(sw1.Elapsed.TotalSeconds).ToString();
label2.Text = Math.Floor(sw2.Elapsed.TotalSeconds).ToString();
}
Note - in a production program I would not use a boolean as my loop checker, you would use an event handle, and probably a couple of event handles if you wanted to allow pausing the updates, this is just to show an idea of how to do it. You could invoke directly from the thread method and drop the InvokeRequired check, but I added that for additional safety and since it was there I skipped it in the loop.
The timer does start immediately. The problem is that you are not reporting fractions of seconds, so the display will show 0 until a full second has elapsed, which is accurate, technically.
If you want to show 1 immediately, just initialize your variables that way.
public Form1() {
InitializeComponent();
sec1 = 1;
sec2 = 1;
}
Hi I'm making a UI in Windform and using timers. It's all quite new to me so my understanding of it is kinda of weak. I use timers to make a side menu animation.
The 1st timer is to show the menu. Something like this :
private void ShowFullToolsTimer_Tick(object sender, EventArgs e)
{
FonctionsNatives.dessinerOpenGL();
if (editionToolsMenu.Width >= 200)
ShowFullTools.Stop();
else
editionToolsMenu.Width += 5;
}
And to hide the side menu I have something similar :
private void HideFullMenu_Tick(object sender, EventArgs e)
{
if (editionToolsMenu.Width > 0)
editionToolsMenu.Width -= 5;
else
HideFullMenu.Stop();
}
The probleme I have is that I want one animation to be COMPLETELY over before starting the other one. I've been using Application.DoEvent(); if the timer.Enable is true, but i'm aware that it's terrible to do that and causes even more bugs. Any solutions?
EDIT1: Sorry for not being precise. Both timer start when a diffrent component is clicked. I also cant write both of the to end, for example:
ShowfullMenu.Start():
HideFullMenu.Start();
Since one does += and the other does -=. They'll be stuck in an infinite loop. Putting the thread to sleep stops the whole UI.
Stop the other timer when you are animating one menu and then restart it once you are done animating (and vice-versa). Here is some non tested code:
private void ShowFullToolsTimer_Tick(object sender, EventArgs e)
{
FonctionsNatives.dessinerOpenGL();
if (editionToolsMenu.Width >= 200)
{
ShowFullTools.Stop();
// start the other one
HideFullMenu.Start();
}
else
{
editionToolsMenu.Width += 5;
if (HideFullMenu.Enabled)
{
HideFullMenu.Stop();
}
}
}
i want realize a simple application that in a specific and precise time, with webbrowser control, go to the webpage.
public partial class Form1 : Form
{
System.DateTime timeStart = new System.DateTime(2016, 05, 25, 19, 30, 00, 00);
TimeSpan sub;
bool timeExpires = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 100;
timer1.Start();
while(timeExpires)
{
webBrowser1.Navigate("https://www.google.it/");
}
}
private void timer1_Tick(object sender, EventArgs e)
{
System.DateTime Now = System.DateTime.Now;
sub = timeStart.Subtract(Now);
if ((int)sub.TotalSeconds == 0)
{
this.timer1.Stop();
MessageBox.Show("ok, Time is up!");
timeExpires = true;
}
else
{
textBox1.Text = sub.ToString();
}
}
}
after the timecount, when timer1.stop() is set, the messagebox is show.
But webbrowser don't run .
I know that i use a bool variable timeExpires is an "antiquated" method.
I have two question :
where is the best pratice or best way to "notify" at webbrowser or any other thing that countdown is finish and now is time to run.
where is problem with this approch(boolean variable)? how I can run with this approch even if isn't the best way?
Thanks so much
You main thread is blocked by the while loop, so the messages/events aren't being processed. That way, the value of timeExpires never changes inside the loop. To you understand, you can Application.DoEvents() to force the events to be processed but it might not be a good unless you really understand how this works and how evil it can be.
You should open the browser inside the Timer's Tick event (just like where you're calling MessageBox.Show()) but be carefully on doing too many things on tick event, if you statements take more time to run than the Timer's interval, the Tick event will run again and might mess up everything. So, to solve this, whatever you enter in the Tick event, pause the timer and start again where you're done.
private void timer1_Tick(object sender, EventArgs e) {
timer1.Stop(); // prevent event to fire again, until we get some stuff done
if(timeStart >= DateTime.Now) {
openBrowser();
} else {
timer1.Start();
textBox1.Text = sub.ToString();
}
}
So I want to perform some button clicks say every in 10 second, and here is my code:
using System;
using System.Timers;
public class Main : Form {
public Main() {
InitializeComponent();
// add timer to do button clicking every 10 seconds
double elapse = 10000;
System.Timers.Timer timer2 = new Time(elapse);
timer2.Elapsed += new ElapsedEventHandler(ResetEvent);
timer2.AutoReset = true;
timer2.Start();
}
private void ResetEvent(object source, ElapsedEventArgs e) {
try {
Refresh_Button.PerformClick();
Process_Button.PerformClick();
} catch { }
}
private void Refresh_Button_Click(object sender, EventArgs e) {
// some code
}
private void Process_Button_Click(object sender, EventArgs e) {
// some code
}
}
However, it doesn't work. Is there anything wrong with the code? How can I make it works?
The problem is accessing UI thread illegally in Elapsed event of System.Timers.Timer.
You are calling Refresh_Button.PerformClick(); in Elapsed event of timer that cause an cross thread exception that you are hiding it.
To access UI thtread and call PerformClick() method of Refresh_Button:
Refresh_Button.Invoke(new Action(() => { Refresh_Button.PerformClick(); }));
Also you can use System.Windows.Forms.Timer instead and handle Tick event and call Refresh_Button.PerformClick(); manually.
Note:
Don't hide exceptions. If you hide exceptions, such problems will hide and finding them will be really hard.
It's better to put the logic a method and instead of calling PerformClick, call that method.
If you don't need a different thread, System.Windows.Forms.Timer whould be enough.
I have a timer of 1 second in C#, with a while sequence in it. My question is if the while sequence is not finished before 1 second, will the timer tick, and restart the while from the beginning?
The part of the code is below, and what it does is that it cycles through the selected objects and changes something. So, if there are a lot of objects selected and I need more than 1 second to change them, will they all be changed?
P.S. I actually want the loop to be broken; a large number of objects will be selected only by mistake, but I just want to be sure that I avoid this possibility. :)
private void timer1_Tick(object sender, EventArgs e)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
}
Yes, timer ticks can happen concurrently. This means that your timer must be thread-safe.
Except for the UI timer classes (WinForms/WPF). Their tick functions run on the UI thread. With DoEvents you can cause reentrancy even there which is another reason to avoid DoEvents.
From the name of the handler I assume you are using System.Windows.Forms.Timer which is single-threaded. That means the Tick event will fire after the previous one has ended. To break the loop, you will have to execute the code in another thread an use an exit condition.
This is how I usually do it:
private bool running;
private bool restart;
private void DoWork(object item)
{
running = true;
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext() && !restart)
{
//do your stuff
if (myEnum.Current != null) {....}
}
if(restart)
{
restart = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (running)
restart = true;
else
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
A workaround would be to disable the timer at the top of the while event, and re-enable it as you exit the while event.
The while loop will not be broken because the timer has ticked again. But in any case, your best bet would be to disable the timer at the beginning of the event handler, and re-enable it again at the end.
You could always try something similar to this instead, that way you void having multiple timers tick over and kick off processes. Written in Notepad so please excuse any massive spelling mistakes
private Timer _systemTimer = null;
public MyApp()
{
_systemTimer = new Timer("how ever you set your 1 second);
// Create your event handler for when it ticks over
_systemTimer.Elapsed += new ElapsedEventHandler(systemTimerElapsed);
}
protected void systemTimerElapsed(object sender, ElapsedEventArgs e)
{
_systemTimer.Stop();
//Do what you need to do
_systemTimer.Start();
//This way if it takes longer than a second it won't matter, another time won't kick off until the previous job is done
}
I will make it very easy for you;use Thread.Sleep() in another background thread and it is done!
If you know when are you finish than just use AutoResetEvent to keep threads in sync.
If you do not have any control on the update no callback , time is unknown I suggest to increase your timer interval!
var thread = new Thread((ThreadStart)delegate
{
While(true)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
Thread.Sleep(1000);
}
}
thread.Start();
Get each char from string from txtString and write on label one by one char with timerControl
int g = 0;
private void timerString_Tick(object sender, EventArgs e)
{
string a = txtString.Text;
int em = txtString.TextLength;
if (g < em)
{
lblString.Text = lblString.Text + a[g];
g++;
}
else timerString.Stop();
}
Call from
private void btnStringStart_Click(object sender, EventArgs e)
{
timerString.Start();
lblString.Text = "";
}