I'm curious as to why dispatcher timer doesn't work in console mode. I created a simple alarm that does something when the timer reaches it's limit.
Can you use dispatcher timer with UnitTest or in Console mode?
DailyAlarm works when I run it in a form.
Here's my code to call the timer
[TestClass]
public class UnitTest1
{
bool runTest = true;
[TestMethod]
public void TestDailyAlarm()
{
DateTime alarmTime = new DateTime();
alarmTime= DateTime.Now;
alarmTime = alarmTime.AddSeconds(5);
// MessageBox.Show(alarmTime.ToString());
DailyAlarm alarm = new DailyAlarm(alarmTime);
alarm.DailyAlarmEvent += alarm_DailyAlarmEvent;
alarm.Start();
while (runTest)
{
System.Threading.Thread.Sleep(1000);
}
}
void alarm_DailyAlarmEvent(EventArgs e)
{
MessageBox.Show("Alarm On");
runTest = false;
}
}
Here's my timer code
public class DailyAlarm
{
#region Timer
DispatcherTimer timer;
#endregion
#region AlarmTime
DateTime _alarmTime;
#endregion
#region Event
public delegate void DailyAlarmHandler(EventArgs e);
public event DailyAlarmHandler DailyAlarmEvent;
#endregion
public DailyAlarm(System.DateTime alarmTime)
{
if (alarmTime < DateTime.Now)
{
alarmTime = alarmTime.AddDays(1);
}
_alarmTime = alarmTime;
TimeSpan timeRemaining = alarmTime.Subtract(DateTime.Now);
timer = new DispatcherTimer();
timer.Tick += AlarmEvent;
timer.Interval = timeRemaining;
}
public void Start()
{
timer.Start();
}
private void AlarmEvent(object sender, EventArgs e)
{
DailyAlarmEvent(null);
// Calculate next Alarm
_alarmTime = _alarmTime.AddDays(1);
TimeSpan timeRemaining = _alarmTime.Subtract(DateTime.Now);
Utilities.DispatcherTimer_ChangeInterval(ref timer, timeRemaining);
}
public void Stop()
{
if (timer != null)
timer.Stop();
}
}
The console and unit test environment by default don't have a dispatcher to run your dispatcher timer.
You can still use Dispatcher.CurrentDispatcher to create a Dispatcher to run your code.
There's an example of its usage at http://consultingblogs.emc.com/crispinparker/archive/2010/10/22/unit-testing-a-wpf-dispatchertimer-method.aspx
With this DispatcherHelper you can test your code with:
[TestMethod]
public void TestMethod1()
{
Action test = () =>
{
var dailyAlarm = new DailyAlarm(DateTime.Now.AddSeconds(5.0));
dailyAlarm.DailyAlarmEvent += dailyAlarm_DailyAlarmEvent;
dailyAlarm.Start();
};
DispatcherHelper.ExecuteOnDispatcherThread(test, 20);
}
void dailyAlarm_DailyAlarmEvent(EventArgs e)
{
// event invoked when DispatcherTimer expires
}
DispatcherTimer fires its Tick event on the UI thread. And you are running your code in a console mode. That's is the answer, I think!
Related
I have a Presence monitor class which is used to detect users active/inactive status. That class has a timer in its Start method which called on application start:
public class PresenceMonitor
{
private volatile bool _running;
private Timer _timer;
private readonly TimeSpan _presenceCheckInterval = TimeSpan.FromMinutes(1);
public PresenceMonitor()
{
}
public void Start()
{
// Start the timer
_timer = new Timer(_ =>
{
Check();
}, null, TimeSpan.Zero, _presenceCheckInterval);
}
private void Check()
{
if (_running)
{
return;
}
_running = true;
// Dowork
}
}
The "Check" method is fired after every one minute. That piece of code is working fine but now my "Do work" methods have become async await so I had to change this Presence Monitor class to something like this:
public class PresenceMonitor
{
private volatile bool _running;
private Timer _timer;
private readonly TimeSpan _presenceCheckInterval = TimeSpan.FromMinutes(1);
public PresenceMonitor()
{
}
public void Start()
{
// Start the timer
var timer = new System.Threading.Timer(async (e) =>
{
await CheckAsync();
}, null, TimeSpan.Zero, _presenceCheckInterval);
}
private async Task CheckAsync()
{
if (_running)
{
return;
}
_running = true;
// await DoworkAsync
}
}
Unfortunately "CheckAsync" method now is getting fired once only instead of every minute. Can you tell me what I am doing wrong here to call async await after regular intervals?
Is there any correct way to do the same?
You could consider creating an event and handler to handle the timer ticks and then invoke your check.
public class PresenceMonitor {
private volatile bool _running;
private Timer timer;
private readonly TimeSpan _presenceCheckInterval = TimeSpan.FromMinutes(1);
public PresenceMonitor() {
Tick += OnTick;
}
public void Start() {
if (_running) {
return; //already running
}
// Start the timer
timer = new System.Threading.Timer(_ => {
Tick(this, EventArgs.Empty);//rasie event
}, null, TimeSpan.Zero, _presenceCheckInterval);
}
private event EventHandler Tick = delegate { };
private async void OnTick(object sender, EventArgs args) {
if (_running) {
return;
}
_running = true;
await DoworkAsync();
}
private Task DoworkAsync() {
//...
}
}
If I understand correctly your requirements, you can get rid of timer and use asynchronous loop.
But you need make Start method asynchronous too
public class PresenceMonitor
{
private volatile bool _running; // possible not needed "volatile" anymore
private readonly int _presenceCheckInterval = 60000; // Milliseconds
public PresenceMonitor()
{
}
public async Task Start()
{
while (true) // may be use some "exit" logic
{
await CheckAsync();
await Task.Delay(_presenceCheckInterval)
}
}
private async Task CheckAsync()
{
if (_running)
{
return;
}
_running = true;
// await DoworkAsync
}
}
Then you can start monitoring
var monitor = new PresenceMonitor();
await monitor.Start();
You can even start monitoring in synchronous way
var monitor = new PresenceMonitor();
monitor.Start(); // Will start monitoring
But approach above is "dangerous" in the way, that any exception thrown inside CheckAsync method will not be propagated. When you start using async-await be ready to "convert" whole application to support it.
i want to run a task every 5 minutes. i've tried to solve it with an IntentService and AlarmManager, my code:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var tkrServiceIntent = new Intent(this, typeof(GpsDataHandler));
var tkrServicePendingIntent = PendingIntent.GetService(this, 0, tkrServiceIntent, 0);
long interval = 5000;
var firstStart = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + 1000;
var am = (AlarmManager)GetSystemService(Context.AlarmService);
am.SetInexactRepeating(AlarmType.RtcWakeup, firstStart, interval, tkrServicePendingIntent);
Toast.MakeText(this, "Service started", ToastLength.Long).Show();
}
i receive the toast, that the service is started, but if i look in running services, there is no service for my application. Can you tell me where the problem ist?
IntentService in an "activity" (if we can call it) runing in Background of the app, so finnally it will call the OnDestroy() ..
You can use the timer to fix your problem , like :
using System;
using System.Threading;
class TimerExampleState {
public int counter = 0;
public Timer tmr;
}
class App {
public static void Main() {
TimerExampleState s = new TimerExampleState();
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate = new TimerCallback(CheckStatus);
// Create a timer that waits one second, then invokes every second.
Timer timer = new Timer(timerDelegate, s, 1000, 1000);
// Keep a handle to the timer, so it can be disposed.
s.tmr = timer;
// The main thread does nothing until the timer is disposed.
while (s.tmr != null)
Thread.Sleep(0);
Console.WriteLine("Timer example done.");
}
// The following method is called by the timer's delegate.
static void CheckStatus(Object state) {
TimerExampleState s = (TimerExampleState) state;
s.counter++;
Console.WriteLine("{0} Checking Status {1}.",DateTime.Now.TimeOfDay, s.counter);
if (s.counter == 5) {
// Shorten the period. Wait 10 seconds to restart the timer.
(s.tmr).Change(10000,100);
Console.WriteLine("changed...");
}
if (s.counter == 10) {
Console.WriteLine("disposing of timer...");
s.tmr.Dispose();
s.tmr = null;
}
}
}
Source : https://developer.xamarin.com/api/type/System.Threading.Timer/
Hope this code helps you:-
async void StartTimer()
{
await Task.Delay(60000); //60 seconds
// Do your code
StartTimer(); // Again Call
}
Call "StartTimer()" method where you want to. Call only once time then it calls automatically after 60 seconds.
Thanks !!!
you can create your own timer using xamarin forms device class
sample timer class:
public class Timer {
public Timer(int interval)
{
_interval = TimeSpan.FromMilliseconds(interval);
}
private bool _isRunning;
private readonly TimeSpan _interval;
private Action Tick;
public void Start(Action tick)
{
_isRunning = true;
Tick = tick;
Xamarin.Forms.Device.StartTimer(_interval,() =>
{
Tick?.Invoke();
return _isRunning;
});
}
public void Stop()
{
_isRunning = false;
Tick = null;
}
}
Create a service class. Call DoWork method in OnStartCommand method. Check whether the log is getting printed after every 5 seconds.
public void DoWork()
{
var t = new Thread(() =>
{
while (true)
{
Log.Debug("Service", "Service running");
Thread.Sleep(5000);
}
});
t.Start();
}
I'm making a WPF application to simulate traffic. I want the Cars to have a reaction delay of 1 second befor changing their acceleration, without stopping the whole application. To do so, I want to acces the elapsed variable from my Car class. The elapsed variable stores how much time has passed.
The code in MainWindow:
namespace TrafficTester
{
public partial class MainWindow : Window
{
Timer timer = new Timer();
public MainWindow()
{
InitializeComponent();
//create the timer
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = timerInterval;
timer.Enabled = true;
//...
void OnTimedEvent(object source, ElapsedEventArgs e)
{
timer.Enabled = false; //stop timer whilst updating, so updating won't be called again before it's finished
update(); //
timer.Enabled = true;
elapsed += timerInterval;
}
}
}
The code in the Car class:
namespace TrafficTester
{
public class Car
{
//...
public void changeAccel(double val)
{
int time = MainWindow.elapsed;
int stop = MainWindow.elapsed + reactDelay;
while (time < stop)
{
time = MainWindow.elapsed;
}
accel = val;
}
}
}
accel is the current acceleration and val is the new acceleration. MainWindow.elapsed should call the elapsed variable from MainWindow, but it doesn't. How can I call it from the Car class?
I saw at least 2 problems:
- If you want to access the timer intance, it needs to be public.
- Then you can access it via an instance of your Mainwindow.
To get the elapsed time, like you probably want, you need to go from you ElapsedEventHandler and do the timing action there!
public partial class MainWindow : Window
{
public System.Timers.Timer myTimer = new System.Timers.Timer();
public MainWindow()
{
//create the timer
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); // Where is it?
myTimer.Interval = 5;
myTimer.Enabled = true;
}
//...
void OnTimedEvent(object source, ElapsedEventArgs e)
{
myTimer.Enabled = false; //stop timer whilst updating, so updating won't be called again before it's finished
//update(); //
myTimer.Enabled = true;
// Timer.Elapsed += 5;
}
}
public class Car
{
public void changeAccel(double val)
{
var myWin = (MainWindow)Application.Current.MainWindow;
int time = myWin.myTimer.Elapsed; //<-- you cannot use it this way
}
}
I'm trying to get weather information using ForecastIOPortable library.
I have a method that works without problems in Console application, same in WPF application.
ForecastApi api = new ForecastApi("XXXX");
var forecast = api.GetWeatherDataAsync(XXXX, XXXX);
var results = forecast.Result;
int tempC = (int)(5.0 / 9.0 * (results.Currently.Temperature - 32));
Problem shows when I try to call that method with tick of timer, program freezes and VS doesn't show information about exception.
When I checked breakpoints, I get information that results doesn't change and all time has value=null.
What is the reason of problem and how to deal with it?
You are using an async process so you will you will be getting the a Task rather than the result.
In a console app you generally have to .Wait() for the task to resolve before the result will be populated. You would be better to test using a WPF application where you can await the GetWeatherDataAsync method.
Probably the best way to handle it is to wrap the timer in a class and pass in the various bits.
You can try this
public class ForecastApiAsyncTimer : IDisposable
{
private ForecastApi _api;
private Timer _timer;
public ForecastApiAsyncTimer(Timer timer, ForecastApi forecastApi)
{
if (timer == null)
throw new ArgumentNullException("timer");
if (forecastApi == null)
throw new ArgumentNullException("forecastApi");
_api = forecastApi;
_timer = timer;
_timer.Elapsed += _timer_Elapsed;
}
public ForecastApiAsyncTimer(double interval, ForecastApi forecastApi)
{
if (forecastApi == null)
throw new ArgumentNullException("forecastApi");
_api = forecastApi;
_timer = new Timer(interval);
_timer.Elapsed += _timer_Elapsed;
}
public void Start()
{
_timer.Start();
}
public void Stop()
{
_timer.Stop();
}
protected async virtual Task<int> TimerElapsedTask()
{
var forecast = await _api.GetWeatherDataAsync(40.7505045d, -73.9934387d);
int tempC = (int)(5.0 / 9.0 * (forecast.Currently.Temperature - 32));
return tempC;
}
async void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
int result = await TimerElapsedTask();
// do something with result.
}
~ForecastApiAsyncTimer()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing || _timer == null)
return;
_timer.Dispose();
_timer = null;
}
}
Example usage 1.
static void Main(string[] args)
{
string apiKey = "yourApiKey";
ForecastApi api = new ForecastApi(apiKey);
using (var forecastTimer = new ForecastApiAsyncTimer(5000, api))
{
forecastTimer.Start();
while (!Console.KeyAvailable)
{
}
}
}
Example usage 2:
static void Main(string[] args)
{
string apiKey = "yourApiKey";
ForecastApi api = new ForecastApi(apiKey);
Timer timer = new Timer(5000);
var forecastTimer = new ForecastApiAsyncTimer(timer, api);
forecastTimer.Start();
while (!Console.KeyAvailable)
{
}
}
I am trying to wrap my head around threading in C# but I am having difficulty implementing this behavior.
I need a simple yes/no dialog that returns DialogResult.No when 30 seconds are passed.
What I've got so far is this:
Thread th = new Thread(() =>
{
try
{
result = message.ShowDialog();
}
catch (Exception)
{
}
});
th.Start();
Thread.Sleep(30000);
th.Abort();
When I select Yes or No on the dialog it still waits out the 30 seconds, I need the thread to stop when response is received.
This is probably a no brainer but I'm relatively new to C# and could really use some help on this.
You could use a Timer when you initialize your Form.
When the timer expired, you close your Form.
Timer time1 = new Timer();
time1.Elapsed += new ElapsedEventHandler(OnTimedEvent);
time1.Interval = 30000; // 30 secs
...
time1.Enabled = true; // Start the timer
message.ShowDialog();
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
// Close your Form
message.Close();
// Maybe you could set a variable, that indicates you, that the timer timed out
}
You have to overwrite ShowDialog() and ShowDialog(owner). When your show dialog will be called you start a timer and forward to the base.ShowDialog(). When the timer raises the tick event simply call Close().
Here an example implementation:
public partial class FormTimed : Form
{
private String _OriginalText;
private DateTime _StartTime;
private Timer _Timer;
public FormTimed()
{
InitializeComponent();
InitializeTimer();
Duration = TimeSpan.FromSeconds(10);
}
[DefaultValue(typeof(TimeSpan), "00:00:10")]
public TimeSpan Duration { get; set; }
public override string Text
{
get
{
return _OriginalText;
}
set
{
_OriginalText = value;
base.Text = value;
}
}
public void DisableTimer()
{
_Timer.Stop();
base.Text = _OriginalText;
}
public void ResetTimer()
{
_StartTime = DateTime.UtcNow;
_Timer.Start();
}
public new DialogResult ShowDialog()
{
StartTimer();
return base.ShowDialog();
}
public new DialogResult ShowDialog(IWin32Window owner)
{
StartTimer();
return base.ShowDialog(owner);
}
private void InitializeTimer()
{
_Timer = new Timer();
_Timer.Interval = 100;
_Timer.Tick += OnTimerTick;
}
private void OnTimerTick(object sender, EventArgs e)
{
var finishTime = _StartTime + Duration;
var remainingDuration = finishTime - DateTime.UtcNow;
if (remainingDuration < TimeSpan.Zero)
{
Close();
}
base.Text = _OriginalText + " (" + (int)remainingDuration.TotalSeconds + ")";
}
private void StartTimer()
{
_StartTime = DateTime.UtcNow;
_Timer.Start();
}
}