Comment faire la distinction entre les clics et les double-clics (Windows Forms .NET)

En règle générale, un seul clic lance une action d’interface utilisateur et un double-clic étend l’action. Par exemple, un clic sélectionne habituellement un élément et un double-clic modifie l'élément sélectionné. Toutefois, les événements de clic Windows Forms ne gèrent pas facilement les scénarios dans lesquels un clic et un double-clic effectuent des actions incompatibles, car une action liée à l'événement Click ou MouseClick est effectuée avant l'action liée à l'événement DoubleClick ou MouseDoubleClick. Cette rubrique illustre deux solutions à ce problème.

Important

La documentation du Guide du bureau pour .NET 7 et .NET 6 est en cours de construction.

Une solution consiste à gérer l'événement de double-clic et à annuler les actions dans la gestion de l'événement de clic. Dans de rares cas, vous devrez peut-être simuler le comportement de clic et de double-clic en gérant l'événement MouseDown et en utilisant les propriétés DoubleClickTime et DoubleClickSize de la classe SystemInformation. Vous mesurez le délai entre les clics et si un deuxième clic se produit avant que la valeur de DoubleClickTime soit atteinte et que le clic se trouve dans un rectangle défini par DoubleClickSize, vous exécutez l'action de double-clic ; sinon, vous exécutez l'action de clic.

Pour annuler une action de clic

Assurez-vous que le contrôle que vous utilisez a un comportement de double-clic standard. Si ce n'est pas le cas, activez le contrôle avec la méthode SetStyle. Gérez l'événement de double-clic et annulez les actions de clic et de double-clic. L'exemple de code suivant montre comment créer un bouton personnalisé avec double-clic activé et comment annuler l'action de clic dans le code de gestion de l'événement de double-clic.

Cet exemple de code utilise un nouveau contrôle de bouton qui active les double-clics :

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

Le code suivant montre comment un formulaire modifie le style de bordure en fonction d’un clic ou double-clic du nouveau contrôle de bouton :

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

Pour faire la distinction entre les clics

Gérez l’événement MouseDown et déterminez l’emplacement et l’intervalle de temps entre les clics à l’aide de la SystemInformation propriété et d’un Timer composant. Exécutez l'action appropriée selon qu'un clic ou un double-clic se produit. L'exemple de code suivant montre comment procéder.

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

Voir aussi