Pregunta

Necesito poder manejar el evento doble clic y solo clic en el StackPanel de WPF. Pero no existe el evento DoubleClick de StackPanel. Quiero hacer 2 operaciones diferentes en estos 2 EventHandlers.

¿Alguna idea de cómo hacer eso?

Gracias

¿Fue útil?

Solución

La mejor manera es corregir su propio controlador de botón del mouse con un tiempo de espera: si el evento se vuelve a activar dentro del período de tiempo de espera, active su mensaje de doble clic; de lo contrario, llame al controlador de un solo clic. Aquí hay un código de muestra ( Editar: originalmente encontrado aquí ):

/// <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);
        }
    }
}

Luego, en el control que desea recibir los eventos:

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

Otros consejos

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

Luego, en el controlador de eventos:

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

Debería funcionar. Tenga en cuenta que un solo clic en el StackPanel golpearía el evento (pero fallará la verificación if)

... años después. La solución de @ MoominTroll es perfectamente aceptable. Otra opción es envolver el panel de la pila en un control de contenido que admita el evento de doble clic.

<ContentControl MouseDoubleClick="DoubleClickHandler" >
    <StackPanel>

    </StackPanel>
</ContentControl>

Otra opción es agregar un MouseBinding a InputBindings en StackElement y luego agregar un CommandBinding que se activa mediante MouseBinding. En general, esta es una mejor práctica que los mecanismos basados ??en eventos porque evita los problemas de pérdida de memoria causados ??por referencias fuertes. También proporciona la separación de la lógica de comando de la representación.

Dicho esto, no es tan sencillo y adjunto al evento lo convierte en un gran atajo.

Y no hace falta decir, haga que el fondo de su panel de pila sea al menos transparente o no será atrapado por la prueba de clic del mouse cuando haga clic en el "fondo". Los fondos nulos se omiten mediante la detección de golpes.

Tuve un problema similar (responda al evento de un solo clic y haga un trabajo adicional en caso de evento de doble clic). Resolví el problema de esta manera:

1) define y declara algún número entero para contener la marca de tiempo del último clic

int lastClickTimestamp;

2) en el método Window_Loaded, inicialice la variable previamente declarada con un número mayor que 200

lastClickTimestamp = 1000;

3) agregue el controlador del botón del mouse a su panel de pila

stackPanel.MouseLeftButtonUp += new MouseButtonEventHandler(stackPanel_MouseLeftButtonUp);

4) agregar el siguiente método

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

        //single click
    }

Este código es inútil si necesita detectar por separado el evento de un solo clic y doble clic. Esa situación introduce un poco más de complejidad, pero definitivamente se puede resolver.

Respuesta completa usando WPF DispatcherTimer . Creamos el temporizador a pedido y lo desconectamos cuando se hace para evitar la obstrucción de recursos.

El 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();
 };

El 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>

Hay una solución más fácil para hacer esto.

En el evento PreviewMouseLeftDown de StackPanel (por ejemplo), puede verificar si la propiedad MouseButtonEventArgs.ClickCount tiene un valor de 2. 1 = solo clic 2 = Doble clic

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top