通常,单击一次会启动一个用户界面操作,双击可扩展该操作。 例如,一键通常选择一项,双击可编辑所选项。 但是,Windows 窗体的单击事件不容易适应这种场景:单击和双击执行不兼容的操作,因为绑定到 Click 或 MouseClick 事件的操作会在绑定到 DoubleClick 或 MouseDoubleClick 事件的操作之前执行。 本主题演示了此问题的两种解决方案。
一种解决方案是处理双击事件,并在处理单击事件时回滚操作。 在极少数情况下,可能需要通过处理MouseDown事件和使用DoubleClickTimeDoubleClickSize类的属性SystemInformation来模拟单击和双击行为。 测量单击之间的时间,如果在达到 DoubleClickTime 值之前发生第二次单击,并且单击位于定义的 DoubleClickSize 矩形内,则执行双击动作;否则执行单击动作。
回退点击操作
确保正在使用的控件具有标准的双击行为。 否则,请用SetStyle方法启用控件。 处理双击事件并回滚单击操作和双击操作。 下面的代码示例演示了如何创建启用了双击功能的自定义按钮,以及如何在双击事件处理代码中回滚单击操作。
此代码示例使用启用双击的新按钮控件:
public partial class DoubleClickButton : Button
{
    public DoubleClickButton()
    {
        // Set the style so a double click event occurs.
        SetStyle(ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true);
    }
}
Public Class DoubleClickButton : Inherits Button
    Public Sub New()
        SetStyle(ControlStyles.StandardClick Or ControlStyles.StandardDoubleClick, True)
    End Sub
End Class
以下代码演示窗体如何基于单击或双击新按钮控件更改边框样式:
public partial class Form1 : Form
{
    private FormBorderStyle _initialStyle;
    private bool _isDoubleClicking;
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        _initialStyle = this.FormBorderStyle;
        var button1 = new DoubleClickButton();
        button1.Location = new Point(50, 50);
        button1.Size = new Size(200, 23);
        button1.Text = "Click or Double Click";
        button1.Click += Button1_Click;
        button1.DoubleClick += Button1_DoubleClick;
        Controls.Add(button1);
    }
    private void Button1_DoubleClick(object sender, EventArgs e)
    {
        // This flag prevents the click handler logic from running
        // A double click raises the click event twice.
        _isDoubleClicking = true;
        FormBorderStyle = _initialStyle;
    }
    private void Button1_Click(object sender, EventArgs e)
    {
        if (_isDoubleClicking)
            _isDoubleClicking = false;
        else
            FormBorderStyle = FormBorderStyle.FixedToolWindow;
    }
}
Partial Public Class Form1
    Private _initialStyle As FormBorderStyle
    Private _isDoubleClicking As Boolean
    Public Sub New()
        InitializeComponent()
    End Sub
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim button1 As New DoubleClickButton
        _initialStyle = FormBorderStyle
        button1.Location = New Point(50, 50)
        button1.Size = New Size(200, 23)
        button1.Text = "Click or Double Click"
        AddHandler button1.Click, AddressOf Button1_Click
        AddHandler button1.DoubleClick, AddressOf Button1_DoubleClick
        Controls.Add(button1)
    End Sub
    Private Sub Button1_DoubleClick(sender As Object, e As EventArgs)
        ' This flag prevents the click handler logic from running
        ' A double click raises the click event twice.
        _isDoubleClicking = True
        FormBorderStyle = _initialStyle
    End Sub
    Private Sub Button1_Click(sender As Object, e As EventArgs)
        If _isDoubleClicking Then
            _isDoubleClicking = False
        Else
            FormBorderStyle = FormBorderStyle.FixedToolWindow
        End If
    End Sub
End Class
区分不同类型的点击
使用MouseDown属性和SystemInformation组件处理事件并确定单击Timer之间的位置和时间跨度。 执行相应的作,具体取决于是单击还是双击。 下面的代码示例演示如何执行此作。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace project
{
    public partial class Form2 : Form
    {
        private DateTime _lastClick;
        private bool _inDoubleClick;
        private Rectangle _doubleClickArea;
        private TimeSpan _doubleClickMaxTime;
        private Action _doubleClickAction;
        private Action _singleClickAction;
        private Timer _clickTimer;
        public Form2()
        {
            InitializeComponent();
            _doubleClickMaxTime = TimeSpan.FromMilliseconds(SystemInformation.DoubleClickTime);
            _clickTimer = new Timer();
            _clickTimer.Interval = SystemInformation.DoubleClickTime;
            _clickTimer.Tick += ClickTimer_Tick;
            _singleClickAction = () => MessageBox.Show("Single clicked");
            _doubleClickAction = () => MessageBox.Show("Double clicked");
        }
        private void Form2_MouseDown(object sender, MouseEventArgs e)
        {
            if (_inDoubleClick)
            {
                _inDoubleClick = false;
                TimeSpan length = DateTime.Now - _lastClick;
                // If double click is valid, respond
                if (_doubleClickArea.Contains(e.Location) && length < _doubleClickMaxTime)
                {
                    _clickTimer.Stop();
                    _doubleClickAction();
                }
                return;
            }
            // Double click was invalid, restart 
            _clickTimer.Stop();
            _clickTimer.Start();
            _lastClick = DateTime.Now;
            _inDoubleClick = true;
            _doubleClickArea = new Rectangle(e.Location - (SystemInformation.DoubleClickSize / 2), 
                                             SystemInformation.DoubleClickSize);
        }
        private void ClickTimer_Tick(object sender, EventArgs e)
        {
            // Clear double click watcher and timer
            _inDoubleClick = false;
            _clickTimer.Stop();
            _singleClickAction();
        }
    }
}
Imports System.Drawing
Imports System.Windows.Forms
Public Class Form2
    Private _lastClick As Date
    Private _inDoubleClick As Boolean
    Private _doubleClickArea As Rectangle
    Private _doubleClickMaxTime As TimeSpan
    Private _singleClickAction As Action
    Private _doubleClickAction As Action
    Private WithEvents _clickTimer As Timer
    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        _doubleClickMaxTime = TimeSpan.FromMilliseconds(SystemInformation.DoubleClickTime)
        _clickTimer = New Timer()
        _clickTimer.Interval = SystemInformation.DoubleClickTime
        _singleClickAction = Sub()
                                 MessageBox.Show("Single click")
                             End Sub
        _doubleClickAction = Sub()
                                 MessageBox.Show("Double click")
                             End Sub
    End Sub
    Private Sub Form2_MouseDown(sender As Object, e As MouseEventArgs) Handles MyBase.MouseDown
        If _inDoubleClick Then
            _inDoubleClick = False
            Dim length As TimeSpan = Date.Now - _lastClick
            ' If double click is valid, respond
            If _doubleClickArea.Contains(e.Location) And length < _doubleClickMaxTime Then
                _clickTimer.Stop()
                Call _doubleClickAction()
            End If
            Return
        End If
        ' Double click was invalid, restart 
        _clickTimer.Stop()
        _clickTimer.Start()
        _lastClick = Date.Now
        _inDoubleClick = True
        _doubleClickArea = New Rectangle(e.Location - (SystemInformation.DoubleClickSize / 2),
                                         SystemInformation.DoubleClickSize)
    End Sub
    Private Sub SingleClickTimer_Tick(sender As Object, e As EventArgs) Handles _clickTimer.Tick
        ' Clear double click watcher and timer
        _inDoubleClick = False
        _clickTimer.Stop()
        Call _singleClickAction()
    End Sub
End Class