I have an Async DataGrid loading feature. Hence, i need to call WaitFor(). Here's that code:
WaitFor(TimeSpan.Zero, DispatcherPriority.SystemIdle);
And following are the 2 methods. Can someone explain what this methods are exactly doing?
public static void WaitFor(TimeSpan time, DispatcherPriority priority)
{
DispatcherTimer timer = new DispatcherTimer(priority);
timer.Tick += new EventHandler(OnDispatched);
timer.Interval = time;
DispatcherFrame dispatcherFrame = new DispatcherFrame(false);
timer.Tag = dispatcherFrame;
timer.Start();
Dispatcher.PushFrame(dispatcherFrame);
}
public static void OnDispatched(object sender, EventArgs args)
{
DispatcherTimer timer = (DispatcherTimer)sender;
timer.Tick -= new EventHandler(OnDispatched);
timer.Stop();
DispatcherFrame frame = (DispatcherFrame)timer.Tag;
frame.Continue = false;
}
You do not need any WaitFor(). Why waiting for something anyways? Just let the UI thread unfrozen and once data loaded the DataGrid will display them.
The methods you posted are doing the.... WaitFor mechanism. The method name explains it all :)
Here are few more details:
DispatcherTimer is a simple dumb Timer you might already know from basic C# just once tick method invoked it will be executed directly on UI thread, hence you do not need to care whether you are on UI thread or not. You always are :)
DispatcherTimer has a prority means if proprity set to high the tick invocation method will be called immediately after interval. If proprity is set to Background the tick method will be invoked when UI thread is not busy.
DispatcherFrame is the current scope you are in. Every displatcher operation has sort of scope. Each scope processes pending work items
Dispatcher.PushFrame is same as DoEvent() back when people used WinForms alot. To keep it simple with DoEvent you are forcing UI thread to do something.
To sum up you wait for things to get done in UI thread.
I hope this helps you any futher.
Related
Two questions.
One: in a winforms application is it a good or bad idea to have a system.timers.timer be enabled and disabled inside of it's elapsed event so that the main UI thread can have access to variables and methods that were created on that main UI thread? So for example with code:
myElapsedTimerEvent(object sender, ElapsedEventArgs args)
{
timer.enabled = false;
/***Call some functions and manipulate some variables***/
timer.enabled = true;
}
Two: In anyone's experience, what are some precautions and dangers to be warned about the system.timers.timer in winform and c#? Are there any examples that you can provide about things that could happen with the hardware and/or software if a timer is not used properly?
Any suggestions for using system.timers.timer would be much appreciated.
Thanks for reading.
It is safe to set the Enabled property of a timer from inside the event handler, provided that the event handler is executed in the UI thread. Otherwise it is not safe, because the System.Timers.Timer class is not thread-safe. The make the handler execute in the UI thread you must set the SynchronizingObject property of the timer to the current Form. For example:
public Form1()
{
InitializeComponent();
timer = new Timers.Timer(5000);
timer.Elapsed += Timer_Elapsed;
timer.SynchronizingObject = this;
timer.AutoReset = true;
}
If I am not mistaken, this assignment happens automatically when you use the designer to add a Timer in a Form.
My suggestion though is to use the System.Windows.Forms.Timer, because it comes without thread-safety considerations. You are not restricted to only one timer. You can have as many of them as you want. Just keep in mind that their handlers are running in the UI thread, so you should avoid putting lengthy code in there, otherwise the responsiveness of the UI may suffer.
What I want to do. I want to SomeMethod will be called periodically. Therefore, I want to timer will be started from backgroung thread after body of background thread method is passed. _timer.Start() was invoked, but TickHandler doesn't;
code:
using Timer = System.Windows.Forms.Timer;
class TestTimer
{
private Timer _timer;
private Thread _thread;
public TestTimer()
{
// create and initializing timer. but not started!
_timer = new Timer();
_timer.Tick += TickHandler;
_timer.Interval = 60000; // 1 minute
// create and start new thread
_thread = new Thread(SomeMethod);
_thread.Start();
}
private void TickHandler(object sender, EventArgs e)
{
// stop timer
_timer.stop();
//some handling
// run background thread again
_thread = new Thread(SomeMethod);
_thread.Start();
}
private void SomeMethod()
{
// some operations
// start timer!
TimerStart();
}
private void TimerStart()
{
_timer.Start();
}
}
By monkey method I found if add Delegate like this
internal delegate void TimerDelegate();
And replace string
TimerStart();
with
Application.Current.Dispatcher.Invoke(new TimerDelegate(TimerStart), null);
all works fine. Somebody can explain me what is the trick?
You've got things mixed up a bit.
If you want a timer that fires on a background thread, you don't have to create a thread to start it (it doesn't matter which thread calls the Start method). Just use System.Timers.Timer, and each Elapsed event will occur on a thread-pool thread.
If you want a timer that fires on the UI thread, since it looks like you're using WPF, you should use System.Windows.Threading.DispatcherTimer, and not the Windows Forms timer you've been using. You should create the timer (i.e. call new) on a particular UI thread, and every Tick event will occur on that thread. Again, it doesn't matter from which thread you call Start.
Here's an explanation of what's happening in your code: You're starting a Windows Forms timer on a non-UI thread. This kind of timer requires a message pump to be running on that thread so it can receive messages. Because it's a non-UI thread, there's no message pump. When you used the Dispatcher.Invoke method, you marshaled the creation of the timer back to the application's main UI thread, which made it work. But it is all quite redundant. If you want to keep the code as is, just replace the timer with a DispatcherTimer, and then you'll be able to remove the Invoke call.
Alternatively, if you're using .NET 4.5 you could use await/async to make this all much easier (be sure to call SomeMethod from the UI thread):
async Task SomeMethod(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await Task.Run(() => DoAsyncStuff(), ct);
DoUIStuff();
await Task.Delay(TimeSpan.FromMinutes(1), ct);
}
}
MSDN can explain it for you:
Note The Windows Forms Timer component is single-threaded, and is
limited to an accuracy of 55 milliseconds. If you require a
multithreaded timer with greater accuracy, use the Timer class in the
System.Timers namespace.
Let me start from saying that it's more a question than a problem that needs to be solved. I have the solution now and things work fine for me. But I wonder why problem occured first time.
This is the code I have right now and it works like I expect:
private void OnNewGameStarted(Game game)
{
_activeGames.Add(game);
TimeSpan delay = game.GetTimeLeft();
var timer = new Timer(delay.TotalMilliseconds) {AutoReset = false};
timer.Elapsed += (sender, args) => GameEndedCallback(game);
timer.Start();
}
private void GameEndedCallback(Game game)
{
if (_statisticsManager.RegisterGame(game))
_gamesRepository.Save(game);
_gameStatusSubscriber.GameStatusChanged(game);
}
I used to use System.Threading.Timer instead of System.Timers.Timer and sometimes timer event (GameEndedCallback method) fired and sometimes not. I couldn't find any reason why it was that way.
This is the code I used to initilize timer (other parts are the same):
TimeSpan delay = game.GetTimeLeft();
new Timer(GameEndedCallback,game,(int)delay.TotalMilliseconds,Timeout.Infinite);
}
private void GameEndedCallback(object state)
{
var game = (Game) state;
Method OnNewGameStarted is event handler and it is called after chain of methods from Fleck webserver when some certain message comes to it.
There is a post about the 3 timer types and what they do.
the main things are:
System.Timers.Timer is for multithreading work
System.Windows.Forms.Timer - from the application UI thread
System.Threading.Timer - not always thread safe!
Timeout.Infinite is The time interval between invocations of callback, in milliseconds. Specify Timeout.Infinite to disable periodic signaling. See MSDN: http://msdn.microsoft.com/en-us/library/2x96zfy7.aspx
Timeout.Infinite is a constant used to specify an infinite waiting period.
Try this to get perodic calls to the callback
new System.Threading.Timer(GameEndedCallback, game, (int)delay.TotalMilliseconds, (int)delay.TotalMilliseconds);
I'm really struggling with this. I'm creating a winforms application in visual studio and need a background timer that ticks once every half hour - the purpose of this is to pull down updates from a server.
I have tried a couple of different approaches but they have failed, either due to poor tutorial/examples, or to my own shortcomings in C#. I think it would be a waste of time to show you what I have tried so far as it seems what I tried was pretty far off the mark.
Does anyone know of a clear and simple way of implementing an asynchronous background timer that is easily understandable by a C# newbie?
// Create a 30 min timer
timer = new System.Timers.Timer(1800000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
...
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
// do stuff
}
with the usual caveats of: timer won't be hugely accurate and might need to GC.KeepAlive(timer)
See also: Why does a System.Timers.Timer survive GC but not System.Threading.Timer?
Declare member variable in your form:
System.Timers.Timer theTimer;
On form load (or whatever other time you need to start update polling), do:
theTimer = new System.Timers.Timer(1800000);
theTimer.Elapsed += PollUpdates;
theTimer.Start();
Declare your PollUpdates member function like this:
private void PollUpdates(object sender, EventArgs e)
{
}
I think you need to know about all timer classes. See Jon's answer below.
What kind of timer are you using?
System.Windows.Forms.Timer will execute in the UI thread
System.Timers.Timer executes in a thread-pool thread unless you
specify a SynchronizingObject
System.Threading.Timer executes its callback in a thread-pool thread
In all cases, the timer itself will be asynchronous - it won't "take up" a thread until it fires.
Source: Do .NET Timers Run Asynchronously?
I got a little problem with my application.
I would like to update something on my UI every 10 seconds. I first used a DispatcherTimer for this but it will block my UI for a short time because the update method needs to load something from the web and this operation needs some time.
Now I thought about some kind of background worker and I found BackgroundTasks.
The problem with Background tasks is, as far as I understood it correctly, that they are supposed to serve as updaters even if the app is suspended. I don't need that.
I only would like to update if my app is running not if it is suspended.
Is there a good way to solve this?
Any suggestions what to use for this?
Thanks in advance!
You need two things for it:
Timer
You can update the UI in System.Timers.Timer with the 10 seconds interval.
Dispatcher
You need to use Dispatcher.Invoke to change the UI without holding the main UI thread. Instead the method Process should be called on a separate thread (Timer method), other than main UI thread, and use Dispatcher in it to alert main UI thread for the change.
Process() // method to be called after regular interval in Timer
{
// lengthy process, i.e. data fetching and processing etc.
// here comes the UI update part
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
}
You need to create a thread that runs the part of your code that gets and processes the information from the website. This way, your form will not hesitate because it will be on a different thread than the processing part.
This Article on code-project should get you started.
Also, you could start a timer, which has a elapsed event, that occurs every time the timer passes a certain time cycle.
http://www.dotnetperls.com/timer
The other answers are missing proper cleanup: When the timer fires in the exact moment that the window was closed, I would get an uncaught TaskCanceledException when trying to run Dispatcher.Invoke. I didn't find help for this problem in other questions. I was able to solve it by unregistering the timer callback when closing the window.
public partial class MainWindow : Window
{
Timer clockTimer = null;
public MainWindow()
{
clockTimer = new Timer(1.0); // 1 ms update to test for TaskCanceledException
clockTimer.Elapsed += Timer_Elapsed;
clockTimer.AutoReset = true;
clockTimer.Start();
Closed += (object sender, EventArgs e) => { clockTimer.Elapsed -= Timer_Elapsed; };
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e) {
var now = DateTime.Now;
Dispatcher.Invoke((Action)delegate () {
UpdateTime(now);
});
}
}
Obviously this is not a good idea if the window was re-shown. I tried adding a dtor, but it would never get called, probably due to cyclic dependencies.
Disclaimer: I don't know C#, so this might not be the best or proper way of doing things.