用于WPF显示的计时器行为异常

时间:2018-07-29 09:37:23

标签: c# .net wpf

我在WPF中制作了一个带有多个按钮的面板。 当鼠标进入某个按钮时,新按钮会出现,并在鼠标离开1000毫秒后消失。

但是我有一个奇怪的行为:在某些情况下,每次使用后1000毫秒会越来越短。

计时器事件

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函数调用计时器:

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();
}

离开按钮时的事件:

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);
}

如代码中所述,我有buttonA和buttonB。当我输入buttonA时,出现miniButton1-鼠标离开事件后1000毫秒它将消失。 对于buttonB来说,这也揭示了miniButton2。

如果我只进入和离开buttonB,一切都正确。与ButtonA相同。 问题:如果我输入/退出按钮A和B,那么这1000毫秒就会越来越短。 miniButton的消失也出现在我离开按钮A和B之前。也发生在我离开按钮之前。

所有的行为都像是计时器彼此混淆一样。 你知道如何解决吗?

2 个答案:

答案 0 :(得分:1)

每次触发Timer事件时,您将重新创建一个新的MouseLeave,如果您碰巧在1000ms内两次触发了该事件,则将在之前重新创建一个新的Timer执行前一个Tick的{​​{1}}事件,这将使前一个Timer无限期运行。

这是在1000毫秒内两次触发Timer事件时发生的情况:

MouseLeave

我能够通过在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. 事件中停止计时器来修正您的代码

MouseEnter

如您的帖子评论中所述,您不应每次都创建一个新的 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; } ,并且应该在处理完毕后立即将其丢弃。另外,除非确实有必要,否则在WPF项目中引用Forms是一个坏主意,这种情况很少。您可能需要阅读关于Storyboard的UI动画。

答案 1 :(得分:0)

所以基本上这是在鼠标离开时发生的:

creating the timer
starting the timer

这会在计时器到期时发生:

stopping the timer

因此,如果鼠标反复进入并留下一个按钮,它将继续创建和启动新计时器。导致多个计时器同时运行。

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();
}

尽管评论中提到的问题更多,但这应该可以解决该问题。