【问题标题】:How can I catch both single-click and double-click events on WPF FrameworkElement?如何在 WPF FrameworkElement 上同时捕获单击和双击事件?
【发布时间】:2011-01-06 08:54:54
【问题描述】:

我可以像这样在 TextBlock 上捕获单击

private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
    MessageBox.Show("you single-clicked");
}

我可以像这样在 TextBlock 上捕获 双击

private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        if (e.ClickCount == 2)
        {
            MessageBox.Show("you double-clicked");
        }
    }
}

但我如何在一个 TextBlock 上同时捕捉它们并区分两者?

【问题讨论】:

  • 用户如何区分它们?

标签: c# wpf event-handling double-click


【解决方案1】:

如果您需要检测差异,我建议您使用 Label 等为您工作的控件:

label.MouseDown += delegate(object sender, MouseEventArgs e)
{
    if (e.ClickCount == 1)
    {
        // single click
    }
};

label.MouseDoubleClick += delegate
{
    // double click
};

编辑:我的建议来自 MSDN 上的文档:

Control 类定义了 PreviewMouseDoubleClick 和 MouseDoubleClick 事件,但不是 相应的单击事件。到 查看用户是否点击了 控制一次,处理MouseDown 事件(或其对应物之一)和 检查 ClickCount 属性是否 值为 1。

但是,即使用户单击,这样做也会给您一个单击通知。

【讨论】:

  • +1 建议使用标签,没有意识到它与 TextBlock 不同,它是从 Control 继承的,但实际上在我的应用程序中我收到了一个 FrameworkElement,所以我需要一些不使用 Control 的解决方案。
  • "但是,即使用户单击,这样做也会为您提供单击通知。" - 你的意思是即使用户双击点击它也会给你一个点击,对吧?
  • 这根本不起作用。双击后您仍然会得到 MouseDown,并且 e.ClickCount 将等于 1。
【解决方案2】:

您需要在点击序列结束后触发事件……那是什么时候?我建议使用计时器。 MouseDown 事件将重置它并增加点击次数。当计时器间隔过去时,它会调用以评估点击次数。

    private System.Timers.Timer ClickTimer;
    private int ClickCounter;

    public MyView()
    {
        ClickTimer = new Timer(300);
        ClickTimer.Elapsed += new ElapsedEventHandler(EvaluateClicks);
        InitializeComponent();
    }

    private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
    {
        ClickTimer.Stop();
        ClickCounter++;
        ClickTimer.Start();
    }

    private void EvaluateClicks(object source, ElapsedEventArgs e)
    {
        ClickTimer.Stop();
        // Evaluate ClickCounter here
        ClickCounter = 0;
    }

干杯!

【讨论】:

  • @kelton52,我试图展示它是如何工作的。使用“MouseLeftButtonDown”事件或任何其他符合您需求的事件。
  • This MSDN code sample 展示了如何创建附加行为,如果在系统双击时间内单击元素两次,则该行为将运行双击命令,否则将运行单击命令。
【解决方案3】:

您必须使用计时器来区分两者。在 GUI 中为您的表单添加一个计时器(最简单的方式 - 它会自动处理处置等......)。在我的示例中,计时器称为clickTimer

private bool mSingleClick;

private void TextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{

    if (e.Button == MouseButtons.Left)
    {
        if (e.ClickCount < 2)
        {
            mSingleClick = true;
            clickTimer.Interval = System.Windows.Forms.SystemInformation.DoubleClickTime;
            clickTimer.Start();
        }
        else if (e.ClickCount == 2)
        {
            clickTimer.Stop();
            mSingleClick = false;
            MessageBox.Show("you double-clicked");
        }
    }
}

private void clickTimer_Tick(object sender, EventArgs e)
{
    if (mSingleClick)
    {
        clickTimer.Stop();
        mSingleClick = false;
        MessageBox.Show("you single-clicked");
    }
}

【讨论】:

    【解决方案4】:

    您可以在 MouseUp 而不是 MouseDown 上执行此操作。这样您就可以向ClickCount 属性询问总点击次数,然后决定从该点开始做什么。

    【讨论】:

    • ...但这无济于事,如果您需要区分单击和双击,即仅处理双击,如果它实际上是单击,并且仅单击,如果它真的是一个......
    【解决方案5】:

    我是这样做的,效果很好

    If e.Clicks = 2 Then
                doubleClickTimer.Stop()
            ElseIf e.Clicks = 1 Then
                doubleClickTimer.Enabled = True
                doubleClickTimer.Interval = 1000
                doubleClickTimer.Start()
    
    
            End If
    
    
     Private Sub doubleClickTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles doubleClickTimer.Tick
    
            OpenWebPage("abc")
            doubleClickTimer.Stop()
        End Sub
    

    【讨论】:

      【解决方案6】:

      您可以简单地使用MouseDown 事件并计算点击次数,如下所示:

      if (e.ChangedButton == MouseButton.Left && e.ClickCount == 2)
      {
          // your code here
      }
      

      【讨论】:

      • 比其他答案简单得多。
      • ...但没有帮助,如果您需要区分单击和双击,即仅处理双击,如果它实际上是一个,并且仅单击,如果它实际上是一个......
      【解决方案7】:

      这是我的工作解决方案:)

          #region message label click --------------------------------------------------------------------------
      private Timer messageLabelClickTimer = null;
      
      private void messageLabel_MouseUp(object sender, MouseButtonEventArgs e)
      {
        Debug.Print(e.ChangedButton.ToString() + " / Left:" + e.LeftButton.ToString() + "  Right:" + e.RightButton.ToString() + "  click: " + e.ClickCount.ToString());
        // in MouseUp (e.ClickCount == 2) don't work!!  Always 1 comes.
        // in MouseDown is set e.ClickCount succesfully  (but I don't know should I fire one clicked event or wait second click)
      
        if (e.ChangedButton == MouseButton.Left)
        {
          if (messageLabelClickTimer == null)
          {
            messageLabelClickTimer = new Timer();
            messageLabelClickTimer.Interval = 300;
            messageLabelClickTimer.Elapsed += new ElapsedEventHandler(messageLabelClickTimer_Tick);
          }
      
          if (! messageLabelClickTimer.Enabled)                                                 
          { // Equal: (e.ClickCount == 1)
            messageLabelClickTimer.Start();
          }
          else  
          { // Equal: (e.ClickCount == 2)
            messageLabelClickTimer.Stop();
      
            var player = new SoundPlayer(ExtraResource.bip_3short);               // Double clicked signal
            player.Play();
          }
        }
      }
      
      private void messageLabelClickTimer_Tick(object sender, EventArgs e)
      { // single-clicked
        messageLabelClickTimer.Stop();
      
        var player = new SoundPlayer(ExtraResource.bip_1short);                  // Single clicked signal
        player.Play();
      }    
      #endregion
      

      【讨论】:

        【解决方案8】:

        我的问题是在WPF 中的DataGrid 中单击/双击行。出于某种原因,ButtonDown 事件没有触发,只有OnMouseLeftButtonUp 事件触发了。无论如何,我想以与双击不同的方式处理单击。看起来我需要一点时间(我确信解决方案并不完美,但它似乎有效)来提炼问题,直到我把它归结为下面。我创建了一个Task,它调用了一个Action,并且Action 的目标可以通过第二次点击来更新。希望这对某人有帮助!

        private Action _clickAction;
        private int _clickCount;
        
        private void Grid_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Debug.WriteLine("Button Click Occurred");
        
            _clickCount++;
        
            if (_clickCount == 1)
            {
                _clickAction = SingleClick;
            }
        
            if (_clickCount > 1)
            {
                _clickAction = DoubleClick;
            }
        
            if (_clickCount == 1)
            {
                Task.Delay(200)
                    .ContinueWith(t => _clickAction(), TaskScheduler.FromCurrentSynchronizationContext())
                    .ContinueWith(t => { _clickCount = 0; });
            }
        }
        
        private void DoubleGridClick()
        {
            Debug.WriteLine("Double Click");
        }
        
        private void SingleGridClick()
        {
            Debug.WriteLine("Single Click");
        }
        

        【讨论】:

          【解决方案9】:

          我的建议,通过简单地使用TaskUserControl 中实现:

          private int _clickCount = 0;
          protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
          {
              _clickCount = e.ClickCount;
          }
          
          protected override async void OnPreviewMouseUp(MouseButtonEventArgs e)
          {
              if (_clickCount > 1)
              {
                  //apparently a second mouse down event has fired => this must be the second mouse up event
                  //no need to start another task
                  //the first mouse up event will be handled after the task below
                  return; 
              }
          
              await Task.Delay(500);
          
              if (_clickCount == 1)
              {
                  //single click
              }
              else
              {
                  //double (or more) click
              }
          }
          

          当然,所有这些解决方案的缺点是在实际响应用户操作之前会有延迟。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-11
            • 1970-01-01
            • 2018-11-02
            • 2023-03-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-25
            相关资源
            最近更新 更多