Domanda

Devo essere in grado di gestire l'evento doppio clic e singolo clic sullo StackPanel WPF. Ma non esiste l'evento DoubleClick di StackPanel. Voglio fare 2 diverse operazioni in questi 2 EventHandlers.

Qualche idea su come farlo?

Grazie

È stato utile?

Soluzione

Il modo migliore è correggere il gestore dei pulsanti del mouse con un timeout: se l'evento viene generato nuovamente entro il periodo di timeout, quindi attiva il messaggio di doppio clic, altrimenti chiama il gestore di clic singolo. Ecco alcuni esempi di codice ( Modifica: originariamente trovato qui ):

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

Quindi, nel controllo che desideri ricevere gli eventi:

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

Altri suggerimenti

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

Quindi nel gestore dell'evento:

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

Dovrebbe funzionare. Nota che un singolo clic in StackPanel colpirebbe l'evento (ma fallire il controllo if)

... anni dopo. La soluzione di @ MoominTroll è perfettamente accettabile. Un'altra opzione è quella di avvolgere il pannello dello stack in un controllo del contenuto che supporti l'evento doppio clic.

<ContentControl MouseDoubleClick="DoubleClickHandler" >
    <StackPanel>

    </StackPanel>
</ContentControl>

Un'altra opzione è quella di aggiungere un MouseBinding a InputBindings su StackElement e quindi aggiungere un CommandBinding che viene attivato da MouseBinding. Nel complesso, questa è una pratica migliore rispetto ai meccanismi basati sugli eventi perché evita i problemi di perdita di memoria causati da riferimenti forti. Prevede anche la separazione della logica di comando dalla rappresentazione.

Detto questo, non è così semplice e si lega all'evento per creare una scorciatoia.

Ed è ovvio, rendere lo sfondo dello stackpanel almeno trasparente o non verrà catturato dal test del clic del mouse quando si fa clic su " background " ;. Gli sfondi nulli vengono ignorati dal rilevamento dei colpi.

Ho avuto un problema simile (rispondi all'evento singolo clic e esegui un lavoro aggiuntivo in caso di doppio clic). Ho risolto il problema in questo modo:

1) definire e dichiarare un numero intero per contenere il timestamp dell'ultimo clic

int lastClickTimestamp;

2) nel metodo Window_Loaded inizializza la variabile precedentemente dichiarata con un numero maggiore di 200

lastClickTimestamp = 1000;

3) aggiungi il gestore dei pulsanti del mouse al pannello dello stack

stackPanel.MouseLeftButtonUp += new MouseButtonEventHandler(stackPanel_MouseLeftButtonUp);

4) aggiungi il seguente metodo

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

        //single click
    }

Questo codice è inutile se è necessario rilevare separatamente l'evento a singolo clic e doppio clic. Tale situazione introduce un po 'più di complessità, ma sicuramente può essere risolta.

Risposta completa utilizzando WPF DispatcherTimer . Creiamo il timer su richiesta e lo disconnettiamo quando fatto per evitare l'intasamento delle risorse.

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

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>

Esiste una soluzione più semplice per farlo.

Nell'evento PreviewMouseLeftDown di StackPanel (ad esempio), puoi verificare se la proprietà MouseButtonEventArgs.ClickCount ha un valore di 2. 1 = Clic singolo 2 = Doppio clic

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top