Click here to Skip to main content
15,885,366 members
Articles / Programming Languages / C# 4.0
Tip/Trick

Detect a DoubleClick to Prevent a Change in Checkstate

Rate me:
Please Sign up or sign in to vote.
4.75/5 (3 votes)
21 Nov 2013CPOL2 min read 25.3K   1   2
Detects a double-click via an initial and subsequent OnMouseDown event

Introduction

Have you enabled checkboxes in your .NET ListBox, ListView or TreeView, and double-clicked on an item in your view and frustratingly watched the checkstate change, although your double-click was nowhere near the state icon? This tip details how to detect a double-click, and prevent it from activating the ItemCheck event. The other option is to capture and restore the checkstate, which is also provided.

Background

You should be familiar with code behind GUI's, and how modifying an component or control within an event handler can in turn trigger other events.

Using the Code

Your class must inherit from the base class of either ListView, ListBox or TreeView, and the CheckBoxes property must be set to True. Just copy and paste the code into your code.

Just a brief explanation of the code from the bottom up:

OnMouseDown is overridden to detect when a click is about to occur. It captures two things: the item under the mouse down, and a timestamp of the mouse down event. It uses a previous item and a previous timestamp by which to compare the current item and timestamp. It also uses a click counter to count clicks. If the current item matches the previous item in the last mouse down event, and this mouse down event occurs within the maximum time of a system mouse-double-click time, and the click counter is on 2, then a double-click has occurred. The variable bool initialClick is used to distinguish an intialClick from a subsequent click. If a subsequent click occurs within the system double-click time, after an initialClick, given the same item, then a double-click has occurred. Else, if a subsequent click occurs beyond the system double-click time, then this subsequent click is an intialClick itself, so intialClick is set to false, and the clickCount is set to 1 for the next mouse down event. Otherwise, initialClick defaults to true and the clickCount is reset to 0, for some future click.

OnMouseDoubleClick is overridden to reset the variable boolDoubleClick to false, when a double-click has occurred. This allows OnMouseDown to determine whether or not future click pairs are double-clicks or separate single clicks.

OnItemCheck is overridden to only call the base OnItemCheck event when a single-click has occurred, i.e., boolDoubleClick is false. This prevents a client's ItemCheck event handler from being triggered on an item double-click. Also note, that when an item double-click does occur, it maintains the item's checkstate by assigning the ItemCheckEventArgs NewValue property to the CurrentValue property, which properties are the items new checkstate and current checkstate, respectively.

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using System.Text;
 
namespace MyViews
{
  public partial class MyListView: ListView
  {
    public MyListView(): base()
    {
      InitializeComponent();
    }
 
    public MyListView(IContainer container): base()
    {
      container.Add(this);
 
      InitializeComponent();
    }
 
    private bool
      boolDoubleClick = false,
      initialClick = true;
    private int
      // for restoring checkstate upon a double-click
      //imageIndex = -1,
      clickCount = 0;
    DateTime
      currTimeStamp = new DateTime(),
      prevTimeStamp = new DateTime();
    private ListViewItem prevLVItem = null;
    private TimeSpan tSpan = new TimeSpan();
 
    public bool BoolDoubleClick { get { return boolDoubleClick; } }
 
    protected override void OnItemCheck(ItemCheckEventArgs ice)
    {
      // Prevent a double-click from triggering an item check event
      if(!boolDoubleClick)
        base.OnItemCheck(ice);
      else
        ice.NewValue = ice.CurrentValue;
    }
    
    protected override void OnMouseDoubleClick(MouseEventArgs e)
    {
      ListViewItem lvItem = this.GetItemAt(e.X, e.Y);
 
      base.OnMouseDoubleClick(e);
      // Option 2: Restore Checkstate
      //if(lvItem!=null && imageIndex>-1)
      //  lvItem.StateImageIndex = imageIndex;
      boolDoubleClick = false;
    }// end OnMouseDoubleClick
    
    protected override void OnMouseDown(MouseEventArgs e)
    {
      ListViewItem lvItem = this.GetItemAt(e.X, e.Y);
 
      // Option 2: Capture Checkstate to restore upon double-click, see
      // OnMouseDoubleClick above.
      //if(lvItem!=null)
      //  imageIndex = lvItem.StateImageIndex;
      base.OnMouseDown(e);
      boolDoubleClick = false;
      if(lvItem!=null && (initialClick || lvItem==prevLVItem))
      { ++clickCount;
        prevTimeStamp = currTimeStamp;
        currTimeStamp = DateTime.Now;
        tSpan = currTimeStamp - prevTimeStamp;
        if(initialClick || tSpan.TotalMilliseconds<=SystemInformation.DoubleClickTime)
        { if(clickCount==2)
          { boolDoubleClick = true;
            initialClick = true;
            clickCount = 0;
          }
          else
            initialClick = false;
        }
        else if(!initialClick && tSpan.TotalMilliseconds>SystemInformation.DoubleClickTime)
        { initialClick = false;
          clickCount = 1;
        }
        else
        { initialClick = true;
          clickCount = 0;
        }
      }
      prevLVItem = lvItem;
    }// end OnMouseDown
  }// end class MyListView
}// end namespace MyViews  

Points of Interest

BIG NOTE: You cannot debug the code by setting a breakpoint inside OnMouseDown. If you do so, it will never detect a double-click, because the timestamp captures will always occur too far apart, due to the breakpoint. Instead set the break point in either OnItemCheck or OnMouseDoubleClick to see the value of boolDoubleClick change in response to clicks.

History

  • 21st November, 2013: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMy rating of 5 Pin
Bill_Hallahan21-Nov-13 14:17
Bill_Hallahan21-Nov-13 14:17 
GeneralMy vote of 5 Pin
Bill_Hallahan21-Nov-13 14:16
Bill_Hallahan21-Nov-13 14:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.