Reputation: 167
I made a panel with several buttons in WPF. When mouse enter in some button, new buttons appear and will disappear 1000 ms after mouse leave.
But I have a strange behavior: 1000 ms in some case become shorter and shorter after each use.
Timer event
private void TimerEventProcessorForButtonA(Object myObject, EventArgs myEventArgs)
{
_myTimerForButtonA.Stop();
miniButton1.Visibility = System.Windows.Visibility.Hidden;
}
private void TimerEventProcessorForButtonB(Object myObject, EventArgs myEventArgs)
{
_myTimerForButtonB.Stop();
miniButton2.Visibility = System.Windows.Visibility.Hidden;
}
WaitTime functions calling timer:
public void WaitThisTimeAndHideMiniButton1(int givenTime)
{
_myTimerForButtonA = new System.Windows.Forms.Timer();
_myTimerButtonA.Tick += new EventHandler(TimerEventProcessorForForButtonA);
_myTimerForForButtonA.Interval = givenTime;
_myTimerForForButtonA.Start();
}
public void WaitThisTimeAndHideMiniButton2(int givenTime)
{
_myTimerForButtonB = new System.Windows.Forms.Timer();
_myTimerForButtonB.Tick += new EventHandler(TimerEventProcessorForForButtonB);
_myTimerForForButtonB.Interval = givenTime;
_myTimerForForButtonB.Start();
}
Event when leave button:
private void buttonA_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
Border button = sender as Border;
button.Background = (SolidColorBrush)new BrushConverter().ConvertFromString(_colorOut);
WaitThisTimeAndHideMiniButton1(1000); // hide minibuttons
}
private void buttonB_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
Border button = sender as Border;
button.Background = (SolidColorBrush) new BrushConverter().ConvertFromString(_colorOut);
WaitThisTimeAndHideMiniButton2(1000);
}
As described in code, I have buttonA and buttonB. When I enter buttonA, miniButton1 appear - it will disappear 1000 ms after mouse leave event. Same thing for buttonB that reveal miniButton2.
If I only enter and leave buttonB everything is correct. Same as ButtonA. The problem: If I enter/leave buttonA and B, then, these 1000ms go shorter and shorter. Disappearance of miniButton also appear before I leave buttonA and B. also happen before I leave the button.
Eveything behave like if timers were confusing each other. Do you know how to solve it?
Upvotes: 1
Views: 109
Reputation: 1583
You're recreating a new Timer
every time a MouseLeave
event is fired, if you happen to fire that event twice within 1000ms, you'll be recreating a new Timer
before the Tick
event of the previous Timer
execute, which will make the previous Timer
run indefinitely.
Here's what's happening when you fire MouseLeave
event twice within 1000ms :
1) MouseLeave: _myTimerForButtonA is assigned a new Timer instance (ie: Timer1), Tick event registered.
2) MouseLeave: _myTimerForButtonA is assigned a new Timer instance (ie: Timer2), Tick event registered.
3) Timer1.Tick event fires TimerEventProcessorForButtonA, whichs stops _myTimerForButtonA which points to Timer2.
4) Timer2.Tick event fires TimerEventProcessorForButtonA, whichs stops _myTimerForButtonA which points to Timer2 (and is already stopped).
5) Timer1.Tick event fires TimerEventProcessorForButtonA indefinitely, because Timer1 is not referenced anymore and no one will ever call `Stop` on it.
I was able to fix your code by stopping the timer on MouseEnter
event
private void TimerEventProcessorForButtonA(Object myObject, EventArgs myEventArgs)
{
Debug.WriteLine("TimerEventProcessorForButtonA");
_myTimerForButtonA.Stop();
_myTimerForButtonA.Dispose();
miniButton1.Visibility = System.Windows.Visibility.Hidden;
}
private void TimerEventProcessorForButtonB(Object myObject, EventArgs myEventArgs)
{
Debug.WriteLine("** TimerEventProcessorForButtonB");
_myTimerForButtonB.Stop();
_myTimerForButtonB.Dispose();
miniButton2.Visibility = System.Windows.Visibility.Hidden;
}
public void WaitThisTimeAndHideMiniButton1(int givenTime)
{
_myTimerForButtonA = new System.Windows.Forms.Timer();
_myTimerForButtonA.Tick += new EventHandler(TimerEventProcessorForButtonA);
_myTimerForButtonA.Interval = givenTime;
_myTimerForButtonA.Start();
}
public void WaitThisTimeAndHideMiniButton2(int givenTime)
{
_myTimerForButtonB = new System.Windows.Forms.Timer();
_myTimerForButtonB.Tick += new EventHandler(TimerEventProcessorForButtonB);
_myTimerForButtonB.Interval = givenTime;
_myTimerForButtonB.Start();
}
private void buttonA_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
Border button = sender as Border;
button.Background = (SolidColorBrush)new BrushConverter().ConvertFromString(_colorOut);
WaitThisTimeAndHideMiniButton1(1000); // hide minibuttons
}
private void buttonB_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
Border button = sender as Border;
button.Background = (SolidColorBrush)new BrushConverter().ConvertFromString(_colorOut);
WaitThisTimeAndHideMiniButton2(1000);
}
private void buttonA_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
if (_myTimerForButtonA?.Enabled == true)
_myTimerForButtonA.Stop();
miniButton1.Visibility = System.Windows.Visibility.Visible;
}
private void buttonB_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
if (_myTimerForButtonB?.Enabled == true)
_myTimerForButtonB.Stop();
miniButton2.Visibility = System.Windows.Visibility.Visible;
}
As stated in comments of your post, you shouldn't create a new Timer
each time, and you should dispose it once you're done. Also, referencing Forms in a WPF project is a bad idea unless really necessary, which rarely is. You'll probably want to read about Storyboard for UI animation.
Upvotes: 1
Reputation: 17085
So basically this happens on mouse leave:
creating the timer
starting the timer
And this happens when timer expires:
stopping the timer
So if mouse repeatedly enters and leaves a button, it keeps creating and starting new timers. Which causes more than one timer to be running at the same time.
public void WaitThisTimeAndHideMiniButton1(int givenTime)
{
if(_myTimerForButtonA != null && _myTimerForButtonA.Enabled)
{
_myTimerForButtonA.Stop();
}
_myTimerForButtonA = new System.Windows.Forms.Timer();
_myTimerButtonA.Tick += new EventHandler(TimerEventProcessorForForButtonA);
_myTimerForForButtonA.Interval = givenTime;
_myTimerForForButtonA.Start();
}
Although there are more issues here as mentioned in comments, this should fix that problem.
Upvotes: 0