Real-time Zedgraph does not respond - c#

My real-time does not respond any more when I change focus from it to another program. I.e. it gets stuck.
Could you please suggest me a possible reason and/or solution for this.

Because your GUI thread (background) isn't beeing processed, when it looses focus, your Zedgraph isn't updated. If you move a window over the ZedGraph, it isn't replotted. Instead you will see the focused window. That's my first guess. Since I don't know your programming language and code, I will just show the principle in C#.
A timer or a new data event calls a function RealTimeGraph. The clue is that an extra thread besides the GUI thread calls RealTimeGraph. The Systems.Timers.Timer class already does that for you. Which Timer or BackgroundWorker to use depends on your application.
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(RealTimeGraph)
Public void RealTimeGraph(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
PeriodicUpdateHandler update = new PeriodicUpdateHandler(this.RealTimeGraph);
this.BeginInvoke(periodic_update,sender, e);
}
else
{
Update(); // check if new data for ZedGraph is available
ZedGraph.GraphPane.AxisChange(); // optional, if ZedGraphAxis has to be recomputed
ZedGraph.control.Invalidate(); // optional
ZedGraph.control.Refresh(); // now the update is visible
}
}
Additionaly it might be handy to call RealTimeGraph, if you focus your application again. Just add a new focus event handler.
this.Enter += new System.EventHandler(this.RealTimeGraph);
I hoped to show you the advantages of this concept.
Verbose ZedGraph with timer
General handy examples on codeproject

Related

How can I prevent duplicate items on view initalization for c# mvvm type application?

I'm making an application that consists of a blank main view and 2 user controls, main view is only used as a container to switch between the 2 user controls by using MVVM Light messenger to tell the main view to switch which user control is displayed.
On startup I have the UserControl1 displaying. I have a button that will show UserControl2. I set up a timer in the Xaml codebehind for UserControl2 that will be used as an inactivity timer to switch back to UserControl1 if inactive.
It is now evident that I am not cleaning up my data properly because after the timer_tick and moving back to UserControl1, I see my timer is still active and ticking. On top of that, when I navigate back to UserControl2, another timer is created and this keeps happening every time I move to this view.
I'm new to c# app development and mvvm, so I'm still trying to figure out how to clean and dispose of my data, so I'm not sure what a standard practice would be.
Could anybody suggest the proper way to ensure I'm not leaking memory for my views and viewmodels?
Edit:
Here is a section of my code behind that I am currently using
public partial class AddQualityRegisterView : UserControl
{
DispatcherTimer timer = new DispatcherTimer();
public AddQualityRegisterView()
{
InitializeComponent();
Debug.WriteLine("AddQualityRegisterView Initialized");
timer.Interval = TimeSpan.FromSeconds(15);
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
Debug.WriteLine("Timer Ticked!!!!!!!!!!!!!!!");
var vm = (AddQualityRegisterViewModel)DataContext;
timer.Stop();
Debug.WriteLine("Timer Stopped");
vm.ExitCommand.Execute(null);
}
If you're using the System.Timers.Timer component, it implements IDisposable. In that case you'd want something like:
using(var timer = new System.Timers.Timer())
{
// Do your stuff here
}
Then whenever you exit that using block, the timer will be disposed of cleanly.
It looks like you are creating a new instance of UserControl2 view everytime you click the "button" to show it - this is not a best practice as far as MVVM is concerned (Though, this is a different story). Given your existing code, I believe you need to remove the handler to properly deal with the timer.
You can remove the handler by:
timer.Tick -= timer_Tick;

VB.net forms application... what event to use when loading initial data

I'm writing a forms application. I'm adding a piece that allows you to double click on a row of a datagridview control to open a new form with more details. These additional details are pulled from a database, which takes a bit of time to finish.
If I run the DB query from the form's load event, the form doesn't show up until everything in the load event has completed, which can take several seconds.
I want the form to show up instantly when you double click, and all of the fields to be populated once the data is ready.
Is there an event I should be using other than Load?
The standard way to accomplish this is to use a background worker thread and disable the button until the worker thread completes. There is a complete event you can subscribe to on the background worker.
You should use threading. Kick off a thread to do the data retrieval in the form's load event. Introduction to threading
You should use a BackgroundWorker to load the data in a background thread without freezing the UI.
If you really want to load on the UI thread, you should handle the Shown event.
This is an c# example using BackgroundWorker as the other posts metioned that loads unit definitions from .xml an file and changes the status label when it finishes. I stuck in the form intializer, but maybe it is better to start it in an OnLoad() override.
public MainForm()
{
InitializeComponent();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = false;
bw.WorkerSupportsCancellation = false;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
unitsToolStripLabel.Text = "Loading Units";
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
...
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
unitsToolStripLabel.Text = string.Format("{0} Units Loaded", Units.UnitLibrary.WorkingSet.Count);
unitsToolStripLabel.LinkBehavior = LinkBehavior.HoverUnderline;
unitsToolStripLabel.Click += new EventHandler(unitsToolStripLabel_Click);
}
Please explain a little more on why you do not want to use threading/backgroundworker?
Whilst the correct way to do this is the BackgroundWorker thread, a quick and dirty method is to start a timer on the Load event and get the data when the timer expires. Say 10ms is enough for the form to be painted, then you can disable the controls and set the cursor busy while you get the data. But this is still going to lock up the UI thread while the database is busy leading to repainting artifacts eg if part of the window is covered, and doesn't allow you to display progress using a progress bar.
You can let the load event finish, then start another method to pull data from your database. The initialization of the UI can be done after the form has completed loading, but make sure your UI controls are disabled while you're initializing them.

Weird Winforms Bug?

I'm making a Calendar application for myself to use, and to learn.
I've had no trouble until now with mutliple forms, and opening new ones on top of each other, etc.
Here's an example:
private void button1_Click(object sender, EventArgs e)
{
if (ceForm != null) ceForm.Close();
ceForm = new CalendarEventForm();
ceForm.Show();
}
Anyway, I now started to add timers to pop up a 'reminder' form before important events on my calendar will occur (i.e. 1 hour before etc.).
The code sets up the timers when the program is loaded, and then when each timer elapses, this is called:
static void lazyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
mainForm.ShowReminder((sender as LazyTimer).ReferredEvent);
}
LazyTimer is exactly the same as a System.Timers.Timer except the added propery 'ReferredEvent', which refers to the calendar event that is to be reminded of.
MainForm.ShowReminder() is as follows:
public void ShowReminder(LazyEvent lazyEvent)
{
ReminderForm newReminder = new ReminderForm();
newReminder.LoadEvent(lazyEvent);
newReminder.Show();
}
The weird thing is that ReminderForm crashes. I've tried it with other forms (such as CalendarEventForm, which I know works normally) and they crash too. However, when I try to load the ReminderForm by pressing a button on my main form, it works fine.
Why do my forms crash when loaded (indirectly) by a timer?
Short answer: Use a System.Windows.Forms.Timer, not a System.Timers.Timer.
The reason is that the System.Timer.Timers class will fire the timer event on another thread, and you are not able to directly do UI operations from another thread than the main UI thread.
If it's wrapping a System.Timers.Timer, it will be firing on a thread-pool thread, which means you can't do UI operations there.
Use a System.Windows.Forms.Timer instead, or set the SynchronizingObject in the System.Timers.Timer to a UI object, so that the timer will fire on the UI thread.
EDIT: Another point... personally I'd probably use a lambda expression or anonymous method as the timer's Tick event handler, capturing the relevant event that way and thus avoiding the extra class and the extra method:
// Presumably we've got a local variable here, e.g. currentEvent
timer.Tick += delegate { mainForm.ShowReminder(currentEvent; };
You are running into a threading issue.
Please use System.Windows.Forms.Timer when working with System.Windows.Forms.
The System.Timers.Timer does not invoke the event on the applications event loop, but calls the event handler directly, which leads, in your case, to a cross thread operation which is not supported by Forms, and your application crashes.
In contrast, System.Windows.Forms.Timer will fit seamlessly into the component model of System.Windows.Forms.

How bad is it to open a new Form using System.Timers.Timer?

My c# WinForm application uses the Elapsed event of a System.Timers.Timer to open a new form. It was pointed out to me (in an earlier question I posted on a different topic) that this was a bad idea; it was suggested I use System.Windows.Forms.Timer.
I've changed my code in response to this suggestion and my application appears to work; however, I'm still rather low on the WinForms learning curve and I'd enjoy feedback on whether or not I've correctly changed my code. (I'm concerned because the old way--the bad way--also appeared to work.)
I have two forms: frmTimer and frmUser. Each form resides in a separate project in the WinForms solution. FrmTimer uses the namespace 'svchostx' and runs from svchostx.exe. FrmUser uses the namespace 'XXXUser' and runs from XXXUser.exe (where XXX is the application's name).
Is it bad to use System.Timers.Timer in this context and, if it is, then have I made the correct changes?
In frmTimer this code:
this.tmTimer= new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)(this.tmTimer)).BeginInit();
//
// tmTimer
//
this.tmTimer.Interval = 20000;
this.tmTimer.SynchronizingObject = this;
this.tmTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.tmTimer_Elapsed);
private System.Timers.Timer tmTimer;
private void tmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
Was replaced with this code:
this.timer1 = new System.Windows.Forms.Timer(this.components);
//
// timer1
//
this.timer1.Interval = 20000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
private System.Windows.Forms.Timer timer1;
private void timer1_Tick(object sender, System.EventArgs e) {
In both the old code and the new code, the timer event checks to see if certain conditions are meet, and when they're meet, then frmUser is opened. FrmUser shows a quiz screen (with math or spelling questions) that the user answers. FrmTimer is never seen and contains only logic to determine when frmUser is opened.
Also, Visual Studio's IntelliSense says this about System.Windows.Forms.Timer: "This timer is optimized for use in Windows Forms applications and must be used in a window." The last part of that sentence confuses me because frmTimer doesn't really have a window (the form is never seen). I'm not sure what is meant by 'must be used in a window'--yes, I am pretty low on the learning curve.
Any advice or help here is appreciated.
The way you are using the System.Timers.Timer is correct. The key to making this timer work in UI scenarios is the SynchronizingObject property. When set to null this timer raises the Elapsed event on a ThreadPool thread. When set to an instance of an ISynchronizeInvoke object it raises the event on the thread hosting that object. If that ISynchronizeInvoke instance is none other than a control or form then the hosting thread is the thread that the control or form was created on...the main UI thread.
The System.Windows.Forms.Timer can only be used in UI scenarios because it creates a window handle. You do not actually see this window get created, but it is there. And of course this timer always raises its Tick event on the UI thread.
Use System.Windows.Forms.Timer for interaction with WinForms.
System.Timers.Timer is built for other purposes, like background operations and services, and its not synchronized with UI Threads.
Have also a look here.
Read about the three types of timers available in .net from here. There is really nothing wrong with using the System.Windows.Forms.Timer for UI programming.
If two windows are created in the same thread, then anything which stalls the UI thread for one will stall it for both. On the other hand, controls from one window can freely manipulate the other window without requiring any explicit synchronization. If you use a forms.Timer, your new window can only be created when the UI is idle; unless you endeavor to make it otherwise, your new form will use the same thread as the one with the timer. If you use another type of timer, your new form can appear even when all other UI threads are busy; the new form will not share a thread with other forms. Note that since the form's thread won't die until the form is closed, it may be better to create a new thread (from the timer event) than hog a thread-pool thread.

Why is this C# timer code not working?

I need to be able to disable a button for 1.5 seconds at a time for an application I'm writing. An image is displayed, a user clicks a button, and then another image is displayed. I need to make sure that the user doesn't click the button again too quickly.
So, when the image is displayed, I call this function:
//when a new image is displayed, start the timer and disable the 'done' button
//for 1.5 seconds, to force people to stop pressing next so quickly
System.Timers.Timer mTimer;
void TimerStart() {
Done.IsEnabled = false;
mTimer = new System.Timers.Timer();
mTimer.Interval = 1500;
mTimer.Start();
mTimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerEnd);
}
The TimerEnd code looks like:
void TimerEnd(object sender, EventArgs eArgs) {
if (sender == mTimer){
Done.IsEnabled = true;
mTimer.Stop();
}
}
The 'Done.IsEnabled' line gets hit, but the button is not reenabled and the timer doesn't stop firing. What am I doing wrong here? If it matters, this is a WPF app.
Use DispatcherTimer instead
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(someInterval);
timer.Tick += new EventHandler(someEventHandler);
timer.Start();
private void someEventHandler(Object sender, EventArgs args)
{
//some operations
//if you want this event handler executed for just once
// DispatcherTimer thisTimer = (DispatcherTimer)sender;
// thisTimer.Stop();
}
Basically you are trying to debounce the button, to prevent too quick clicks. Rather than use a timer save the previous click time in millis, if the button is clicked again within a short time ignore the next event.
The timer event is raised on a different thread. When working with the winforms controls, you need to make sure you Invoke them from the same thread where they were called.
When working with WPF there is no guarantee that updates made to UI controls on non-UI threads will work as expected. In many cases you will get an exception when you do this.
In your Timer elapsed handler you need to use the BeginInvoke/EndInvoke paradigm and put your button enabling logic in there to ensure that this code runs on the UI thread instead of Begin/End Invoke
There is a SynchnornizationContext available as well which can be accessed by calling SynchronizationContext.Current . You'll need to cache this before you make the timer call since SynchronizationContext.Current will be null in non-UI threads.
This link talks about this as well.

Categories