web-dev-qa-db-ja.com

WPF FrameworkElementでシングルクリックイベントとダブルクリックイベントの両方をキャッチするにはどうすればよいですか?

次のように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");
        }
    }
}

しかし、1つのTextBlockで両方をキャッチし、2つを区別するにはどうすればよいですか?

20
Edward Tanguay

クリックシーケンスが終了した後にイベントを発生させる必要があります...それはいつですか?タイマーを使うことをお勧めします。 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;
    }

乾杯!

12
Natxo

違いを検出する必要がある場合は、Labelなどのコントロールを使用することをお勧めします。

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

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

編集:私のアドバイスはMSDNのドキュメントからのものでした:

Controlクラスは、PreviewMouseDoubleClickイベントとMouseDoubleClickイベントを定義しますが、対応するシングルクリックイベントは定義しません。ユーザーがコントロールを1回クリックしたかどうかを確認するには、MouseDownイベント(または対応するイベントの1つ)を処理し、ClickCountプロパティ値が1であるかどうかを確認します。

ただし、そうすると、ユーザーがシングルクリックした場合でもシングルクリック通知が表示されます。

3
Kent Boogaart

2つを区別するには、タイマーを使用する必要があります。 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");
    }
}
2
awe

次のように、MouseDownイベントを使用してクリック数をカウントするだけです。

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

私はこのようにそれをしました、そしてそれは完全に働きます

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
1
Kamran

それは私の実用的な解決策です:)

    #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
0
eMeL

私の問題は、DataGridWPFの行をシングル/ダブルクリックすることでした。何らかの理由で、ButtonDownイベントが発生せず、OnMouseLeftButtonUpイベントのみが発生しました。とにかく、私はシングルクリックをダブルクリックとは異なる方法で処理したかったのです。以下に問題が解決するまで問題を抽出するのに少し時間がかかります(解決策は完璧ではないと思いますが、うまくいくようです)。 Taskを呼び出すActionを作成しました。そのActionのターゲットは2回目のクリックで更新できます。これが誰かを助けることを願っています!

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");
}
0
CptCoathanger

MouseDownの代わりにMouseUpでそれを行うことができます。そうすれば、ClickCountプロパティにクリックの総数を尋ね、その時点から何をするかを決めることができます。

私の提案は、単にUserControlを使用してTaskに実装されています。

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

もちろん、これらすべてのソリューションの欠点は、ユーザーのアクションに実際に応答するまでに遅延が発生することです。

0
mike