Вопрос

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

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

Спасибо

Это было полезно?

Решение

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

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

Другие советы

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

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

<ContentControl MouseDoubleClick="DoubleClickHandler" >
    <StackPanel>

    </StackPanel>
</ContentControl>

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

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

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

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

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
    }

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

Полный ответ с использованием 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>

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top