Question

Je dois être capable de gérer les événements double-clic et simple-clic sur le StackPanel WPF. Mais l'événement DoubleClick de StackPanel n'existe pas. Je souhaite effectuer 2 opérations différentes dans ces 2 gestionnaires d’événements.

Avez-vous une idée de comment faire cela?

Merci

Était-ce utile?

La solution

La meilleure solution consiste à redresser le gestionnaire de votre propre bouton de souris avec un délai d'expiration. Si l'événement est déclenché à nouveau dans le délai imparti, déclenchez votre message en double-clic, sinon appelez le gestionnaire de clic simple. Voici un exemple de code ( Modifier: trouvé à l'origine ici ):

/// <summary>
/// For double clicks
/// </summary>
public class MouseClickManager {
    private event MouseButtonEventHandler _click;
    private event MouseButtonEventHandler _doubleClick;

    public event MouseButtonEventHandler Click {
        add { _click += value; }
        remove { _click -= value; }
    }

    public event MouseButtonEventHandler DoubleClick {
        add { _doubleClick += value; }
        remove { _doubleClick -= value; }
    }

    /// <summary>
    /// Gets or sets a value indicating whether this <see cref="MouseClickManager"/> is clicked.
    /// </summary>
    /// <value><c>true</c> if clicked; otherwise, <c>false</c>.</value>
    private bool Clicked { get; set; }

    /// <summary>
    /// Gets or sets the timeout.
    /// </summary>
    /// <value>The timeout.</value>
    public int DoubleClickTimeout { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="MouseClickManager"/> class.
    /// </summary>
    /// <param name="control">The control.</param>
    public MouseClickManager(int doubleClickTimeout) {
        this.Clicked = false;
        this.DoubleClickTimeout = doubleClickTimeout;
    }

    /// <summary>
    /// Handles the click.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
    public void HandleClick(object sender, MouseButtonEventArgs e) {
        lock (this) {
            if (this.Clicked) {
                this.Clicked = false;
                OnDoubleClick(sender, e);
            }
            else {
                this.Clicked = true;
                ParameterizedThreadStart threadStart = new ParameterizedThreadStart(ResetThread);
                Thread thread = new Thread(threadStart);
                thread.Start(e);
            }
        }
    }

    /// <summary>
    /// Resets the thread.
    /// </summary>
    /// <param name="state">The state.</param>
    private void ResetThread(object state) {
        Thread.Sleep(this.DoubleClickTimeout);

        lock (this) {
            if (this.Clicked) {
                this.Clicked = false;
                OnClick(this, (MouseButtonEventArgs)state);
            }
        }
    }

    /// <summary>
    /// Called when [click].
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
    private void OnClick(object sender, MouseButtonEventArgs e) {
        if (_click != null) {
            if (sender is Control) {
                (sender as Control).Dispatcher.BeginInvoke(_click, sender, e);
            }
        }
    }

    /// <summary>
    /// Called when [double click].
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
    private void OnDoubleClick(object sender, MouseButtonEventArgs e) {
        if (_doubleClick != null) {
            _doubleClick(sender, e);
        }
    }
}

Ensuite, dans le contrôle, vous souhaitez recevoir les événements:

MouseClickManager fMouseManager = new MouseClickManager(200);
fMouseManager.Click += new MouseButtonEventHandler(YourControl_Click); 
fMouseManager.DoubleClick += new MouseButtonEventHandler(YourControl_DoubleClick);

Autres conseils

 <StackPanel MouseDown="StackPanel_MouseDown">
   <!--stackpanel content-->
    <TextBlock>Hello</TextBlock>
</StackPanel>

Ensuite, dans le gestionnaire d'événements:

 private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ClickCount >= 2)
        { 
            string hello; //only hit here on double click  
        }
    }

Devrait fonctionner. Notez qu'un simple clic dans StackPanel déclencherait l'événement (mais échouerait si la vérification était si)

... ans plus tard. La solution de @ MoominTroll est parfaitement acceptable. Une autre option consiste à envelopper le panneau de pile dans un contrôle de contenu prenant en charge l'événement en double-clic.

<ContentControl MouseDoubleClick="DoubleClickHandler" >
    <StackPanel>

    </StackPanel>
</ContentControl>

Une autre option consiste à ajouter un MouseBinding aux InputBindings sur StackElement, puis à ajouter un CommandBinding activé par MouseBinding. Dans l’ensemble, c’est une meilleure pratique que les mécanismes à base d’événements car elle évite les problèmes de fuite de mémoire causés par de fortes références. Il permet également de séparer la logique de commande de la représentation.

Cela étant dit, ce n’est pas aussi simple ni attacher à l’événement, c’est un excellent raccourci.

Et cela va sans dire, rendez votre fond d’empilage au moins transparent ou il ne sera pas attrapé par le test de clic sur la souris lorsque vous cliquez sur le "fond". Les arrière-plans nuls sont ignorés par la détection des impacts.

J'ai eu un problème similaire (répondre à un simple clic et effectuer un travail supplémentaire en cas de double clic). J'ai résolu le problème de cette façon:

1) définissez et déclarez un nombre entier comme étant le dernier clic sur l'horodatage

int lastClickTimestamp;

2) dans la méthode Window_Loaded, initialiser la variable précédemment déclarée avec un nombre supérieur à 200

lastClickTimestamp = 1000;

3) ajouter un gestionnaire de bouton de souris à votre panneau de pile

stackPanel.MouseLeftButtonUp += new MouseButtonEventHandler(stackPanel_MouseLeftButtonUp);

4) ajouter la méthode suivante

void stackPanel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (e.Timestamp - lastClickTimeStamp < 200)
        {
            //double click
        }
        lastClickTimeStamp = e.Timestamp;

        //single click
    }

Ce code est inutile si vous devez détecter séparément les événements simple clic et double clic. Cette situation introduit un peu plus de complexité, mais peut certainement être résolue.

Complétez la réponse en utilisant WPF DispatcherTimer . Nous créons le minuteur à la demande et le déconnectons une fois l'opération terminée afin d'éviter tout encrassement des ressources.

Le C #:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;

public partial class MainWindow : Window
{
    DispatcherTimer dt;

    bool clear_timer()
    {
        if (dt == null)
            return false;
        dt.Tick -= _single_click;
        dt = null;
        return true;
    }

    private void _click(Object sender, MouseButtonEventArgs e)
    {
        if (clear_timer())
            Debug.Print("double click");
        else
            dt = new DispatcherTimer(
                        TimeSpan.FromMilliseconds(GetDoubleClickTime()),
                        DispatcherPriority.Normal,
                        _single_click,
                        Dispatcher);
    }

    void _single_click(Object sender, EventArgs e)
    {
        clear_timer();
        Debug.Print("single click");
    }

    public MainWindow() { InitializeComponent(); }

    [DllImport("user32.dll")]
    static extern uint GetDoubleClickTime();
 };

Le XAML:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel Orientation="Horizontal"
                Background="AliceBlue"
                Width="100"
                Height="100"
                MouseLeftButtonDown="_click" />
</Window>

Il existe une solution plus simple.

Dans l'événement PreviewMouseLeftDown de StackPanel (par exemple), vous pouvez vérifier si la propriété MouseButtonEventArgs.ClickCount a la valeur 2. 1 = clic simple 2 = double-clic

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top