MouseEnter定时事件重复

时间:2015-08-05 06:45:39

标签: c# wpf timer hover mouseenter

我有几个按钮,我希望它们在光标定位在指定时间之后执行某些操作。在这种情况下,他们应该只在文本框中写下他们的内容。

这是计时器:

private static System.Timers.Timer myTimer = 
        new System.Timers.Timer(1500);

这是按钮使用MouseEnter事件执行的方法:

private void keysHover(object sender, EventArgs e)
    {
        myTimer.Elapsed += delegate { keysHoverOK(sender); };
        myTimer.Enabled = true;
    }

如果Timer结束,这就是执行的内容:

private void keysHoverOK(object sender)
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            txtTest.Text += (sender as System.Windows.Controls.Button).Content.ToString();
        }));
        myTimer.Enabled = false;

    }

我不太明白为什么会发生这种情况,但是每当其中一个按钮完成Timer时,keysHoverOK方法就会写出与已悬停的字符一样多的字符。例如,如果我将鼠标悬停在按钮A上,则会写入A,如果我将鼠标悬停在按钮B上,则会写入AB,从而获得AAB 1}}写在文本框上等等,句子执行次数与其他按钮执行keysHover方法一样多,即使他们没有完成Timer本身,就像他们的内容被保存在某个地方。当然,我想按钮所做的只是编写内容和内容。所以你知道我做错了什么吗?

2 个答案:

答案 0 :(得分:0)

你的意思是MouseEnter事件吗?我不知道WPF中有任何MouseOver事件。

如果没有a good, minimal, complete code example,就无法确定问题是什么。但是,根据您共享的少量代码和问题描述,您的主要问题似乎是您与多个控件共享一个Timer对象。当一个控件订阅Timer.Elapsed事件时,它永远不会取消订阅,这加剧了这一点。因此,如果另一个控件启用了计时器(也订阅了该事件),则在计时器间隔过去时会通知两个控件。

即使是单个控件也存在问题,因为每次引发MouseEnter事件时它都会自行订阅该事件。

修复是禁用计时器并在鼠标离开控件边界时或在计时器间隔结束时取消订阅事件。这可能看起来像这样:

private EventHandler _timerElapsedHandler;

// Subscribed to the MouseEnter event
private void keysHover(object sender, EventArgs e)
{
    _timerElapsedHandler = delegate { keysHoverOK(sender); };
    myTimer.Elapsed += _timerElapsedHandler;
    myTimer.Enabled = true;
}

// Subscribed to the MouseLeave event
private void keysLeave(object sender, EventArgs e)
{
    DisableTimer();
}

private void keysHoverOK(object sender)
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        txtTest.Text += (sender as System.Windows.Controls.Button).Content.ToString();
    }));
    DisableTimer();
}

private void DisableTimer()
{
    myTimer.Elapsed -= _timerElapsedHandler;
    myTimer.Enabled = false;
    _timerElapsedHandler = null;
}

其他评论:

  • 您应该投射而不是使用as。仅当引用可以合法地使用与您检查的类型不同时才使用as。当它总是应该是您要检查的类型时使用强制转换。这样,如果您有错误,您将获得一个有意义的例外,而不仅仅是一些NullReferenceException
  • 上面的示例修复了代码中断最少的问题。但实际上,我也会做出其他改变。例如,不是将委托存储在字段中,而是获取Content.ToString()值并存储它。然后,我将使用一个命名方法,而不是对委托实例使用匿名方法,该方法只使用存储的string值附加到Text属性。您可以按名称订阅和取消订阅指定的方法;委托类型做正确的事情,即使它使用不同的委托实例进行订阅和取消订阅。
  • 您可能考虑进行的另一项更改是为每个控件使用不同的Timer实例。然后,您不必在鼠标事件发生时订阅或取消订阅;只是在初始化期间订阅。
  • 最后,特别是因为这是WPF代码,你真的应该考虑将附加文本存储在一个可观察的属性中(例如DependencyProperty,或实现INotifyPropertyChanged),并将其绑定到{{1}而不是直接操纵该属性。

答案 1 :(得分:0)

我假设你说:

  

这是按钮使用MouseOver事件执行的方法:

您可能是指MouseEnter事件?

从我看到的内容:

  • 您有一个中央计时器
  • 它会在您输入的第一个按钮
  • 上开始倒计时
  • 如果您在停止该按钮之前没有停止计时器
  • 您似乎只是在不删除任何
  • 的情况下将代理添加到事件中

代码段myTimer.Elapsed += delegate { keysHoverOK(sender); };另一个委托添加到已添加的委托列表中。它不会只用一个代表替换列表。

如果在计时器过去之前离开按钮,则需要使用减号运算符(myTimer.Elapsed -= ....)从计时器已用事件中删除委托,然后停止计时器。这里有一个问题,你已经创建了一个匿名方法,所以你需要: -

  1. 研究removing anonymous methods
    1. 研究removing all event handlers
    2. 或者可能是最简单的menthod

      1. 每次进入按钮时,停止并销毁任何正在运行的计时器并创建一个新的计时器实例。