I am using MvvmLight to develope WPF Application.I want to enabled button when 4 minute is remaining with the settled time.It should automatically enabled in UI.Should I use thread to continuously track difference of CurrentUTCtime and mytime ?If yes ,then How to use thread with this code ? Here is my code.
Datetime mytime = new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,22,0,0)
public RelayCommand Open
{
get
{
return Open?? (_open= new RelayCommand(ExecuteOpen, CanExecuteOpen));
}
private void ExecuteOpen()
{
_navigation.NavigationToSetBetsDialogue();
}
private bool CanExecuteOpen()
{
double? remainingMinutes = null;
DateTime CurrentUTCtime = DateTime.UtcNow;
remainingMinutes = mytime .Subtract(CurrentUTCtime).TotalMinutes;
if (remainingMinutes <= 4)
{
return true;
}
else
{
return false;
}
}
}
Try using a DispatcherTimer:
private DispatcherTimer _Timer = new DispatcherTimer();
private bool _CanExecute;
private void StartTimer()
{
var mytime = new DateTime( DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 22, 0, 0 );
var interval = DateTime.UtcNow - mytime - TimeSpan.FromMinutes( 4 );
_Timer.Interval = interval;
_Timer.Tick += Timer_Tick;
}
private void Timer_Tick( object sender, EventArgs e )
{
_Timer.Tick -= Timer_Tick;
_CanExecute = true;
CommandManager.InvalidateRequerySuggested();
}
public ICommand Open
{
get { return new RelayCommand( ExecuteOpen, () => _CanExecute ); }
}
well you can use can execute and check for elapsed time no need for separate thread as can execute will run on parallel anyway...
private DateTime _startTime;
private void StartCommandHandler(object obj)
{
_startTime = DateTime.Now;
}
private bool CanEnableButton(object arg)
{
return _startTime != DateTime.MinValue && DateTime.Now.Subtract(_startTime).Minutes >= 4;
}
Hope it helps
You can do this with BackgroundWorker. First you need to inititalize worker:
BackgroundWorker bgWrkr = new BackgroundWorker();
bgWrkr.DoWork += new DoWorkEventHandler(bgWrkrDoWork);
bgWrkr.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWrkrRunWorkerCompleted);
Then implement handlers for events. DoWork:
void bgWrkrDoWork(object sender, DoWorkEventArgs e)
{
while (mytime.Subtract(DateTime.UtcNow).TotalMinutes >= 4){ }
}
and RunWorkerCompleted:
void bgWrkrRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button.IsEnabled = true;
}
And sure you have to start worker:
bgWrkr.RunWorkerAsync();
You can start it right after initializing.bgWrkr.RunWorkerAsync();
Related
I am creating a game in visual studio using c sharp and want to add a pop up message saying 'game Over' once the timer reaches 0. Currently the countdown timer goes to negative seconds and the game keeps going. Currently attempt is below and any help is apricated.
public MainPage()
{
InitializeComponent();
_random = new Random(); // r is my random number generator
_countDown = 30;
SetUpMyTimers();// method for my timer
endGame();
}
private void endGame()
{
throw new NotImplementedException();
}
private void SetUpMyTimers() // calling my method
{
// start a timer to run a method every 1000ms
// that method is "TimerFunctions" that runs on the UI thread
Device.StartTimer(TimeSpan.FromMilliseconds(1000), () =>
{
Device.BeginInvokeOnMainThread(() =>
{ TimerFunctions(); });
return true;
});
}
private void TimerFunctions()
{
// change the countdown.
_countDown--;
LblCountdown.Text = _countDown.ToString();
}
The countdown is over to call the function.Use winform timer control to implement countdown function
public partial class Form1 : Form
{
TimeSpan Span = new TimeSpan(0, 0, 10);
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
Span = Span.Subtract(new TimeSpan(0, 0, 1));
label1.Text = Span.Hours.ToString() + ":" + Span.Minutes.ToString() + ":" + Span.Seconds.ToString();//时间格式0:0:10
if (Span.TotalSeconds < 0.0)//when the countdown is over
{
timer1.Enabled = false;
MessageBox.Show("game over");
}
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Interval = 1000;//Set every interval to 1 second
timer1.Enabled = true;
MessageBox.Show("End the game after 10s");
}
}
Test timer:
Hope it helps you.
You could try the following code.
<Grid>
<TextBlock Name="tbTime" />
</Grid>
Codebehind:
DispatcherTimer _timer;
TimeSpan _time;
public MainWindow()
{
InitializeComponent();
_time = TimeSpan.FromSeconds(10);
_timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
{
tbTime.Text = _time.ToString("c");
if (_time == TimeSpan.Zero)
{
_timer.Stop();
MessageBox.Show("GameOver");
}
_time = _time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
_timer.Start();
}
The result:
I want to repeat this notifications every 24 hours.
Temporary i`ve used Thread.Sleep(); but i know this is not good solution.
I think about using Time.Interval BUT I don`t know where to place that methods.
when i set things like aTimer.Elapsed and so on, according the documentation, My program just ignore the fact he need _timePicker input too.
My actual code looks like this
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
readonly INotificationManager notificationManager;
DateTime _triggerTime;
public MainPage()
{
InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerTick);
notificationManager = DependencyService.Get<INotificationManager>();
notificationManager.NotificationReceived += (sender, eventArgs) =>
{
var evtData = (NotificationEventArgs)eventArgs;
ShowNotification(evtData.Title, evtData.Message);
};
}
bool OnTimerTick()
{
if (_switch.IsToggled && DateTime.Now >= _triggerTime)
{
DisplayAlert("Alert", "Time to take your pill! :) ", "OK");
string title = $"Pill Reminder";
string message = $"Take Your Pill :) ";
notificationManager.ScheduleNotification(title, message);
var duration = TimeSpan.FromSeconds(1);
Vibration.Vibrate(duration);
//24h interval, need some better solution
Thread.Sleep(86400000);
}
return true;
}
void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "Time")
{
SetTriggerTime();
}
}
void OnSwitchToggled(object sender, ToggledEventArgs args)
{
SetTriggerTime();
}
void SetTriggerTime()
{
if (_switch.IsToggled)
{
_triggerTime = DateTime.Today + _timePicker.Time;
if (_triggerTime < DateTime.Now)
{
_triggerTime += TimeSpan.FromDays(1);
}
}
}
void ShowNotification(string title, string message)
{
Device.BeginInvokeOnMainThread(() =>
{
var msg = new Label()
{
Text = $"Notification Received:\nTitle: {title}\nMessage: {message}"
};
});
}
}
To achieve this there are many different ways;
repeatedly check for system TimeAndDate and run code once it gets to X.
Shedule a task using a Timer. You can set interval to s/m/h and run code on TimerElapse.
using a Thread Sleep, very very bad way in this case, for many different reasons.
Here's an example sheduling a task:
using System;
using System.Timers;
namespace ScheduleTimer
{
class Program
{
static Timer timer;
static void Main(string[] args)
{
schedule_Timer();
Console.ReadLine();
}
static void schedule_Timer()
{
Console.WriteLine("Timer Start");
DateTime nowTime = DateTime.Now;
//scheduled time HH,MM,SS [24 hours]
DateTime scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, 24, 0, 0, 0);
if (nowTime > scheduledTime)
{
scheduledTime = scheduledTime.AddDays(1);
}
double tickTime = (double)(scheduledTime - DateTime.Now).TotalMilliseconds;
timer = new Timer(tickTime);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Timer Stop");
timer.Stop();
Console.WriteLine("Hello, World!\n");
schedule_Timer();
}
}
}
I have a script based on the countdown timer. I want that when the time reaches 0, the timer stop and a message appear. The code id this:
public partial class simulare : Form
{
private admin admin;
Timer timer = new Timer();
public simulare(admin admin)
{
InitializeComponent();
this.admin=admin;
label2.Text = TimeSpan.FromMinutes(0.1).ToString();
}
private void simulare_Load(object sender, EventArgs e)
{
var startTime = DateTime.Now;
timer = new Timer() { Interval = 1000 };
timer.Tick += (obj, args) =>
label2.Text = (TimeSpan.FromMinutes(0.1) - (DateTime.Now - startTime)).ToString("hh\\:mm\\:ss");
timer.Enabled = true;
timer.Start();
if (condition)
{
timer.Stop();
MessageBox.Show("Done!");
}
}
}
I tried those conditions, but unsuccessful:
if (timer.ToString() == TimeSpan.Zero.ToString())
if (label2.Text.ToString() == TimeSpan.Zero.ToString())
if (label2.Text == TimeSpan.Zero)
You could extract the calculation and assign the result to a TimeSpan variable, then check if the Seconds in that TimeSpan variable are equals to zero
void simulare_Load(object sender, EventArgs e)
{
var startTime = DateTime.Now;
timer = new System.Windows.Forms.Timer() { Interval = 1000 };
timer.Tick += (obj, args) =>
{
TimeSpan ts = TimeSpan.FromMinutes(0.1) - (DateTime.Now - startTime);
label1.Text = ts.ToString("hh\\:mm\\:ss");
if (ts.Seconds == 0)
{
timer.Stop();
MessageBox.Show("Done!");
}
};
timer.Start();
}
First off, checking anything in the Load event isn't going to work. That code only runs once (on form load).
So you need a more complex tick event, which I would put into an actual function instead of a lambda:
private int countDown = 50; //Or initialize at load time, or whatever
public void TimerTick(...)
{
label2.Text = (TimeSpan.FromMinutes(0.1) - (DateTime.Now - startTime)).ToString("hh\\:mm\\:ss");
countDown--;
if (countDown <= 0)
timer.Stop();
}
I use an int counter here since checking against a view property (the text in this case) isn't a very good design/practice. If you really want a TimeSpan, I would still save it off instead of checking directly against the Text property or a string.
I have a requirement where i need to execute timer at 00:01:00 A.M every day...But i am not getting how to achieve this ..If i am taking Systems time,it can be in different format..
Here is my timer code..
static System.Timers.Timer timer;
timer = new System.Timers.Timer();
timer.Interval = 1000 * 60 * 60 * 24;//set interval of one day
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
start_timer();
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// Add timer code here
}
private static void start_timer()
{
timer.Start();
}
If you want to start a timer at exactly 00:01:00am do some processing time and then restart the timer you just need to calculate the difference between Now and the next 00:01:00am time slot such as.
static Timer timer;
static void Main(string[] args)
{
setup_Timer();
}
static void setup_Timer()
{
DateTime nowTime = DateTime.Now;
DateTime oneAmTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, 0, 1, 0, 0);
if (nowTime > oneAmTime)
oneAmTime = oneAmTime.AddDays(1);
double tickTime = (oneAmTime - nowTime).TotalMilliseconds;
timer = new Timer(tickTime);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Stop();
//process code..
setup_Timer();
}
What you should do is write your program that does whatever you need it to do, and then use your OS's built-in task scheduler to fire it off. That'd be the most reliable. Windows's Task Scheduler, for instance, can start your app before the user logs in, handle restarting the app if necessary, log errors and send notifications, etc.
Otherwise, you'll have to run your app 24/7, and have it poll for the time at regular intervals.
For instance, you could change the interval every minute:
timer.Interval = 1000 * 60;
And inside your Elapsed event, check the current time:
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (DateTime.Now.Hour == 1 && DateTime.Now.Minute == 0)
{
// do whatever
}
}
But this is really unreliable. Your app may crash. And dealing with DateTime's can be tricky.
You could always calculate it:
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// Do stuff
start_timer();
}
private static void start_timer()
{
timer.Interval = CalculateInterval();
timer.Start();
}
private static double CalculateInterval()
{
// 1 AM the next day
return (DateTime.Now.AddDays(1).Date.AddHours(1) - DateTime.Now).TotalMilliseconds;
}
Here is a timer implementation which takes an Interval (just like any other timer) and fires exactly when that interval expires, even the machine goes to sleep mode in between.
public delegate void TimerCallbackDelegate(object sender, ElapsedEventArgs e);
public class TimerAbsolute : System.Timers.Timer
{
private DateTime m_dueTime;
private TimerCallbackDelegate callback;
public TimerAbsolute(TimerCallbackDelegate cb) : base()
{
if (cb == null)
{
throw new Exception("Call back is NULL");
}
callback = cb;
this.Elapsed += this.ElapsedAction;
this.AutoReset = true;
}
protected new void Dispose()
{
this.Elapsed -= this.ElapsedAction;
base.Dispose();
}
public double TimeLeft
{
get
{
return (this.m_dueTime - DateTime.Now).TotalMilliseconds;
}
}
public int TimeLeftSeconds
{
get
{
return (int)(this.m_dueTime - DateTime.Now).TotalSeconds;
}
}
public void Start(double interval)
{
if (interval < 10)
{
throw new Exception($"Interval ({interval}) is too small");
}
DateTime dueTime = DateTime.Now.AddMilliseconds(interval);
if (dueTime <= DateTime.Now)
{
throw new Exception($"Due time ({dueTime}) should be in future. Interval ({interval})");
}
this.m_dueTime = dueTime;
// Timer tick is 1 second
this.Interval = 1 * 1000;
base.Start();
}
private void ElapsedAction(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.Now >= m_dueTime)
{
// This means Timer expired
callback(sender, e);
base.Stop();
}
}
}
For performance i have to replace DispatcherTimer with a BackGroundWorker to handle a intensive query that runs every 5 sec by using a Threading Timer.
I no longer get any result when implementing the following code, most of the times my application shuts down as well.
public void CaculateTimeBetweenWegingen()
{
if (listWegingen.Count > 1)
msStilstand = (DateTime.Now - listWegingen[listWegingen.Count - 1]).TotalSeconds;
if(msStilstand >= minKorteStilstand)
{
stopWatch.Start();
if (msStilstand >= minGroteStilstand)
{
FillDuurStilstandRegistrationBtn();
if (zelfdeStilstand == false)
{
CreateRegistrationButton();
zelfdeStilstand = true;
}
if (msStilstand <= maxGroteStilstand){
//....
}
}
}
else //new weging
{
if (stopWatch.IsRunning == true)
{
timerStilstand.Stop();
stopWatch.Stop();
//huidige registrationBtn
if (GlobalObservableCol.regBtns.Count > 1)
{
GlobalObservableCol.regBtns[GlobalObservableCol.regBtns.Count - 1].StopWatchActive = false;
GlobalObservableCol.regBtns[GlobalObservableCol.regBtns.Count - 1].DuurStilstand =
String.Format("{0:D2}:{1:D2}:{2:D2}", stopWatch.Elapsed.Hours, stopWatch.Elapsed.Minutes, stopWatch.Elapsed.Seconds);
}
}
zelfdeStilstand = false;
}
}/*CaculateTimeBetweenWegingen*/
public void CreateRegistrationButton()
{
InitializeDispatcherTimerStilstand();
RegistrationButton btn = new RegistrationButton(GlobalObservableCol.regBtns.Count.ToString());
btn.RegistrationCount = GlobalObservableCol.regBtnCount;
btn.Title = "btnRegistration" + GlobalObservableCol.regBtnCount;
btn.BeginStilstand = btn.Time;
GlobalObservableCol.regBtns.Add(btn);
GlobalObservableCol.regBtnCount++;
btn.DuurStilstand = String.Format("{0:D2}:{1:D2}:{2:D2}", 0, 0, 0);
}
public void InitializeDispatcherTimerWeging()
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
void Worker_DoWork(object sender, DoWorkEventArgs e)
{
TimerCallback callback = MyTimerCallBack;
timerWegingen = new Timer(callback);
timerWegingen.Change(0, 5000);
}
public void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
worker.RunWorkerAsync();
}
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
CaculateTimeBetweenWegingen();
}
The button gets refilled with new values every 1 sec trough a other timer. "DuurStilstand" is a dependency property
private void FillDuurStilstandRegistrationBtn()
{
TimeSpan tsSec = TimeSpan.FromSeconds(stopWatch.Elapsed.Seconds);
TimeSpan tsMin = TimeSpan.FromMinutes(stopWatch.Elapsed.Minutes);
TimeSpan tsHour = TimeSpan.FromMinutes(stopWatch.Elapsed.Hours);
if (GlobalObservableCol.regBtns.Count >= 1
&& GlobalObservableCol.regBtns[GlobalObservableCol.regBtns.Count - 1].StopWatchActive == true)
{
GlobalObservableCol.regBtns[GlobalObservableCol.regBtns.Count - 1].DuurStilstand =
String.Format("{0:D2}:{1:D2}:{2:D2}", tsHour.Hours, tsMin.Minutes, tsSec.Seconds);
}
}
All the above code is written in a separate c# class.
How exactly do i make this code work with BackGroundWorker and how / where to update the GUI with Dispatcher/Invoke. Been trying for a long while and i cannot seem to solve this issue atm.
I have also seen that the Complete method of the BackGroundWorker can be used to update the GUI, but not sure how exactly. The buttons get created and saved in a ObservableCollection.
public static ObservableCollection<RegistrationButton> regBtns = new ObservableCollection<RegistrationButton>();
Some examples would be most useful. Since i know more or less what has to been done but not exactly sure how to implement it.
Best Regards,
Jackz
I don't understand the meaning of your app but you'll be able to update UI like this
public void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, new Action(() =>
{
//do your stuff
}));
}
Maybe the Rendering event should help you to deal with the UIThread.
CompositionTarget.Rendering += (s, args) =>
{
//do your stuff
};
Hope it help