WPF StackPanel с щелчком и двойным щелчком - PullRequest
6 голосов
/ 30 ноября 2009

Мне нужно иметь возможность обрабатывать событие двойной щелчок и одиночный щелчок на WPF StackPanel. Но нет такой вещи как событие DoubleClick от StackPanel. Я хочу сделать 2 разные операции в этих 2 EventHandlers.

Есть идеи, как это сделать?

Спасибо

Ответы [ 7 ]

24 голосов
/ 30 ноября 2009
 <StackPanel MouseDown="StackPanel_MouseDown">
   <!--stackpanel content-->
    <TextBlock>Hello</TextBlock>
</StackPanel>

Затем в обработчике события:

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

Должно работать. Обратите внимание, что один щелчок в StackPanel приведет к событию (но не к проверке if)

7 голосов
/ 11 ноября 2015

... лет спустя. Решение @ MoominTroll вполне приемлемо. Другой вариант - обернуть панель стека в элемент управления содержимым, который поддерживает событие двойного щелчка.

<ContentControl MouseDoubleClick="DoubleClickHandler" >
    <StackPanel>

    </StackPanel>
</ContentControl>
5 голосов
/ 30 ноября 2009

Лучший способ - назначить свой собственный обработчик кнопок мыши тайм-аутом - если событие вызывается снова в течение периода ожидания, затем запустить сообщение о двойном щелчке, в противном случае вызовите обработчик одного щелчка. Вот пример кода ( Edit: , первоначально найденный здесь ):

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

Затем в элементе управления вы хотите получать события:

MouseClickManager fMouseManager = new MouseClickManager(200);
fMouseManager.Click += new MouseButtonEventHandler(YourControl_Click); 
fMouseManager.DoubleClick += new MouseButtonEventHandler(YourControl_DoubleClick);
4 голосов
/ 01 декабря 2009

Другой вариант - добавить MouseBinding к InputBindings в StackElement, а затем добавить CommandBinding, который активируется MouseBinding. В целом это более эффективная практика, чем механизмы, основанные на событиях, потому что это позволяет избежать проблем утечки памяти, вызванных сильными ссылками. Также предусмотрено отделение логики команд от представления.

Это, как говорится, не так просто и присоединение к событию делает отличный путь.

И само собой разумеется, сделайте фон панели стека хотя бы прозрачным, иначе он не будет обнаружен тестом щелчка мыши при нажатии на "фон" Нулевые фоны пропускаются при обнаружении попадания.

0 голосов
/ 02 февраля 2016

Для этого есть более простое решение.

В событии StackPanel PreviewMouseLeftDown (например) можно проверить, имеет ли свойство MouseButtonEventArgs.ClickCount значение 2 1 = один клик 2 = Двойной клик

0 голосов
/ 25 мая 2014

Полный ответ с использованием WPF DispatcherTimer. Мы создаем таймер по требованию и отключаем его по окончании работы, чтобы предотвратить засорение ресурса.

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>
0 голосов
/ 31 января 2013

У меня была похожая проблема (реагировать на одно нажатие и выполнять дополнительную работу в случае двойного щелчка). Я решил проблему следующим образом:

1) определить и объявить некоторое целое число для хранения отметки времени последнего клика

int lastClickTimestamp;

2) в методе Window_Loaded инициализировать ранее объявленную переменную с некоторым числом больше 200

lastClickTimestamp = 1000;

3) добавить обработчик кнопки мыши на панель стека

stackPanel.MouseLeftButtonUp += new MouseButtonEventHandler(stackPanel_MouseLeftButtonUp);

4) добавить следующий метод

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

        //single click
    }

Этот код бесполезен, если вам нужно отдельно определять событие одиночного щелчка и двойного щелчка. Эта ситуация вносит немного больше сложности, но определенно может быть решена.

...