Control.ValueChanged fire with time offset - c#

I have some C# controls like NumericUpDown or TextBox and want to fire an event with an offset of some seconds. In the past, I have accomplished this behaviour with a Timer. The code which I am working on uses a BackgroundWorker to accomplish this. On some other places, I found normal Threads to build this behaviour.
The reason why one might want an offset is, for example, a time-consuming method which is executed after each ValueChange of a NumericUpDown. If a user clicks several times on the down arrow only the last Click should be of importance because this is the value which the user wanted in the end.
The way I used to handle this looks as follows
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
/*
* Designer Code
this.eventOffsetTimer.Interval = 500;
this.eventOffsetTimer.Tick += new System.EventHandler(this.eventOffsetTimer_Tick);
*/
eventOffsetTimer.Stop();
eventOffsetTimer.Start();
}
private void eventOffsetTimer_Tick(object sender, EventArgs e)
{
eventOffsetTimer.Stop();
//Time consuming stuff...
MessageBox.Show(numericUpDown1.Value.ToString());
}
I was wondering what the best practice is to accomplish an offset of some seconds before the event is fired. Is there a built-in way which Microsoft encourages to use? Starting and stopping a Timer is a simple thing to do but it seems there could be a Microsoft encouraged method.

You should use .Restart(). It first releases Timer then Starts it again.
Tips: You do not need to use .Stop() with .Restart()

Related

Real-time Zedgraph does not respond

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

Stopping Multiple Events from Looping

I have a function that is intended to allow my user to move a set of objects (an airport) to a new location.
On the dialog that for this I have four controls - two textboxes that represent coordinates and two numeric up downs one for distance and one for bearing. The user can choose to enter either a distance and bearing or a set of coordinates. This is done via a checkbox and the non used set is disabled. So that the user has feedback I would like to update the disabled pair values as the user enters the enabled pair. If they are entering coordinates then the distance and bearing updates and vice versa.
My method for doing this is to respond to the TextChanged event of each object to update the others. Of course this creates one event firing another and back again as the other control updates. It does not create an infinite loop as far as I can tell but it does mess up the caret position in the active boxes.
I have tried some approaches including including trying to disable events based on which boxes are active or using some bool flags. I also tried using a timer rather than events. It is all very messy and no approach seems to work. I would like to know if there is a better way.
Thanks
Assuming you are using Windows Forms:
// this.ckPosition.CheckedChanged += new System.EventHandler(this.ckPosition_CheckedChanged);
private void ckPosition_CheckedChanged(object sender, EventArgs e)
{
txtX.Enabled = txtY.Enabled = ckPosition.Checked;
numBearing.Enabled = numDistance.Enabled = !ckPosition.Checked;
}
// this.txtX.TextChanged += new System.EventHandler(this.Position_TextChanged);
// this.txtY.TextChanged += new System.EventHandler(this.Position_TextChanged);
private void Position_TextChanged(object sender, EventArgs e)
{
if (ckPosition.Checked)
{
// Replace with your calculations
numBearing.Value = Convert.ToInt32(txtX.Text);
numDistance.Value = Convert.ToInt32(txtY.Text);
}
}
// this.numBearing.ValueChanged += new System.EventHandler(this.BearingDistance_ValueChanged);
// this.numDistance.ValueChanged += new System.EventHandler(this.BearingDistance_ValueChanged);
private void BearingDistance_ValueChanged(object sender, EventArgs e)
{
if (ckPosition.Checked == false)
{
// Replace with your calculations
txtX.Text = numBearing.Value.ToString();
txtY.Text = numDistance.Value.ToString();
}
}
As long as you don't change the position in the position event handler or the bearing/distance in it's handler, there should not be any 'looping' of events.
I know this is probably a big performance no-no but have you tried finding the origin of your event using reflection to tell if it's a forwarded event or not? you could look further up the stack to find out if the event is a forwarded event, or you could abort if the call stack depth gets ridiculous.
Or, if you're calling TextChanged events manually, you could derive from the eventArgs class to pass your own custom eventArgs and then abort if the eventArgs is your custom type or use the custom eventArgs to pass state information to help you.
Or maybe you could swap the TextChanged event that sits on the control with a similar event handler of your own.

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.

C# Form Move Stopped Event

Is there any event in C# that fires when the form STOPS being moved. Not while its moving.
If there is no event for it, is there a way of doing it with WndProc?
The ResizeEnd event fires after a move ends. Perhaps you could use that.
This is not a failsafe solution, but it's pure .NET and it's dead simple. Add a timer to your form, set it to a relatively short delay (100-150 ms seemed OK for me). Add the following code for the Form.LocationChanged and Timer.Tick events:
private void Form_LocationChanged(object sender, EventArgs e)
{
if (this.Text != "Moving")
{
this.Text = "Moving";
}
tmrStoppedMoving.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
tmrStoppedMoving.Start();
this.Text = "Stopped";
}
If you want more exact handling (knowing exactly when the mouse button is release in the title bar and such) you will probably need to dive into monitoring windows messages.
I had the same problem with a user control, but it does not have the ResizeEnd event. The solution, which worked is to override the WndProc method and listen for EXITSIZEMOVE.
See example here
Just set a flag to true when onmove events are fired. If a mouseup event happens and the flag is true, the form stopped being moved.
I admit this probably won't work in the case of a user moving a form via the keyboard, but that's pretty rare.
I tested ResizeChanged event, and it works fine, however I don't know relation between move and resize, but it works for me

C# DateTimePicker stuck in loop

I have a datetimepicker in C#. When I click on it, it expands to show a monthly calendar, when I click the left arrow to go back a month, it changes the value and calls my event. The event includes too much code to include here but it calls several functions needless to say.
The problem I'm having is that when I click that left arrow it gets stuck in some sort of loop and keeps descending through the months and I can't stop it. One of the functions that is being called contains a Application.DoEvents() and if I comment that out it doesn't get stuck in the loop, but I need that command to update another section of the interface. Any idea why this is happening?
I can duplicate it sometimes with this code, sometimes it just does it a couple times, sometimes it gets stuck in the loop.
private void DateTimePickerValueChangedEvent(object sender, EventArgs e)
{
afunction();
}
private void afunction()
{
listView1.Clear();
panel1.Visible = true;
Application.DoEvents();
}
I also have the same problem. In my case, instead of calling DoEvents I'm updating a Crystal Report view. The only workaround I found is to update my view upon the CloseUp event instead of ValueChanged or TextChanged.
Scott, how did you finally corrected your problem ?
The DateTimePicker ValueChanged event is buggy. Per Microsoft Windows Forms Team on this page https://connect.microsoft.com/VisualStudio/feedback/details/1290685/debugging-datetimepicker-event-hangs-vs:
"The DateTimePicker control installs a mouse hook as part of its functionality, but when the debugger has the WinForms application stopped on a breakpoint, it allows the possibility of a deadlock if VS happens to get a mouse message. For now, the deadlock is unfortunately a consequence of the DateTimePicker's design. The mouse hook is installed when the drop down is clicked to display the calendar. This means that breakpoints should not be sent in any event handlers which would be called while the calendar is active. We are currently investigating whether it is possible to address this issue and we will update this thread with further information if we are able to make a fix available."
Without seeing any of the code, try these steps:
Comment out the entire event handler
to see how fast it runs with nothing
attached to it.
Uncomment lines one at a time to see
which ones are causing the most
problems.
Analyze those method calls.
...
Profit!
You could try a couple of things. Get rid of the DoEvents inside of the ChangedEvent.
Call the doevents inside of a seperate function after maybe a period of time (thread.sleep() ?).
I know doevents does cause issues but I rarely use it.
event procedure ValueChanged :
set parameter in sender.tag
enableTimer and execute parameter using sender.tag
example:
private void DateTimePicker_ValueChanged(object sender, EventArgs e)
{
DateTimePicker ThisSender = (DateTimePicker)sender;
Timer.Tag = ThisSender.Name.ToString() + "=" + ThisSender.Value;
Timer.Enabled = true;
}

Categories