2009-11-30 93 views
6

我需要能夠處理雙擊單擊事件在WPF StackPanel上。但是沒有StackPanel的DoubleClick事件。 我想在這2個EventHandlers中做2個不同的操作。WPF StackPanel with Click和DoubleClick

任何想法如何做到這一點?

謝謝

+7

我仍然無法理解微軟怎麼可能人省略這樣的基本功能。 – 2013-01-11 19:41:28

回答

5

,最好的辦法是右鍵一個超時自己的鼠標按鈕的處理程序 - 如果事件在超時時間內再次發射,再火的DoubleClick的消息,否則調用一次點擊處理程序。下面是一些示例代碼(編輯:最初發現here):

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

+1 - 比我的回答全面十億倍 – MoominTroll 2009-11-30 17:15:38

+0

@MoominTroll哈哈,恰好我剛剛在我們的應用程序中實現了這個功能:D – 2009-11-30 17:17:23

+2

我必須讀錯了......每當你開始一個新的線程鼠標點擊,它不是一個雙擊?哇...那是......哼哼......特別的。 請使用「e.ClickCount> = 2」考慮下面的解決方案。 – joce 2010-04-12 19:37:21

23
<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會觸發事件(但如果檢查失敗)

+0

不如處理雙擊事件的性能,但速度不夠快。 +1 – Randolpho 2009-11-30 17:16:11

+0

是的我已經嘗試過..但我需要處理Single和DoubleClick .. clickcount並沒有真正的幫助,因爲它似乎也是doubleclick == singleclick。 – 2009-11-30 17:22:00

+1

@ PaN1C_Showt1Me如何處理'if(e.ClickCount> = 2){HandleDoubelClick(); } else if(e.ClickCount> = 1){HandleSingleClick();}' – joce 2010-04-12 19:40:57

4

另一種方法是將MouseBinding添加到StackElement上的InputBindings,然後添加由MouseBinding激活的CommandBinding。總體而言,這比基於事件的機制更好,因爲它避免了由強引用引起的內存泄漏問題。它還提供了從表示中分離命令邏輯。

這就是說,它不那麼直接,並附加到事件使得一個偉大的捷徑。

不言而喻,讓你的堆棧面板背景至少是透明的,或者當你點擊「背景」時它不會被鼠標點擊測試捕獲。命中檢測跳過空背景。

0

我有類似的問題(響應單擊事件,並在雙擊事件的情況下做一個額外的工作)。我解決了這個問題是這樣的:

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 
    } 

如果您需要單獨檢測單擊和雙擊事件,則此代碼無用。這種情況會帶來更多複雜性,但可以毫無疑問地得到解決。

0

使用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> 
4

...年以後。 @ MoominTroll的解決方案完全可以接受。另一種選擇是將堆棧面板包裝在支持雙擊事件的內容控件中。

<ContentControl MouseDoubleClick="DoubleClickHandler" > 
    <StackPanel> 

    </StackPanel> 
</ContentControl> 
0

有一個更簡單的解決方案來做到這一點。

在StackPanel中的事件PreviewMouseLeftDown(例如),您可以檢查是否MouseButtonEventArgs.ClickCount酒店的2 1 =單次點擊 2 =雙擊值