通常,单击一次会启动一个用户界面操作,双击可扩展该操作。 例如,一键通常选择一项,双击可编辑所选项。 但是,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属性和Timer组件处理事件并确定单击SystemInformation之间的位置和时间跨度。 执行相应的作,具体取决于是单击还是双击。 下面的代码示例演示如何执行此作。
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