c# - 用于具有奇怪行为的 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 毫秒消失。显示 miniButton2 的 buttonB 也是如此。
如果我只进入和离开按钮B,一切都是正确的。与按钮 A 相同。 问题:如果我进入/离开按钮 A 和 B,那么这 1000 毫秒会越来越短。miniButton 的消失也出现在我离开按钮 A 和 B 之前。也发生在我离开按钮之前。
一切的行为就像计时器相互混淆一样。你知道怎么解决吗?
解决方案
Timer
每次触发事件时都会重新创建一个新MouseLeave
事件,如果您碰巧在 1000 毫秒内触发了该事件两次,那么您将在前一次执行的事件Timer
之前重新创建一个新事件,这将使前一次无限期运行。Tick
Timer
Timer
以下是您MouseLeave
在 1000 毫秒内触发两次事件时发生的情况:
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;
}
正如您帖子的评论中所述,您不应该Timer
每次都创建一个新的,并且应该在完成后将其丢弃。此外,在 WPF 项目中引用表单是一个坏主意,除非真的有必要,但这种情况很少发生。您可能想阅读有关UI 动画的Storyboard的内容。
推荐阅读
- python - 当我将空字符串作为参数时,“count”字符串方法会返回什么?
- c++ - std::filesystem / boost::filesystem for mac os
- mysql - Nodejs Expess 脚本无法创建 Mysql 数据库表
- python - 如何将字符串中的数字作为python中的单个元素提取到列表中?
- python - 区分^J和
在诅咒中 - android - 在Android应用程序(Kotlin)中按下按钮时尝试获取最后一个已知位置
- c# - 无法在 .Net 4.6.1 上安装 Dapper 2.0.4
- git - 用旧的 git commit 意外覆盖了本地代码。有什么办法恢复吗?
- vim - 搜索标签时是否可以在 ctags 中提供标签建议?
- python - 更改图形图像的比例