我需要能够处理WPF StackPanel 上的双击和单击事件。但是没有 StackPanel 的 DoubleClick 事件。我想在这 2 个 EventHandlers 中做 2 个不同的操作。
知道怎么做吗?
谢谢
我需要能够处理WPF StackPanel 上的双击和单击事件。但是没有 StackPanel 的 DoubleClick 事件。我想在这 2 个 EventHandlers 中做 2 个不同的操作。
知道怎么做吗?
谢谢
<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 中单击会触发事件(但如果检查失败)
...多年后。@MoominTroll 的解决方案是完全可以接受的。另一种选择是将堆栈面板包装在支持双击事件的内容控件中。
<ContentControl MouseDoubleClick="DoubleClickHandler" >
<StackPanel>
</StackPanel>
</ContentControl>
最好的方法是编写您自己的带有超时的鼠标按钮处理程序 - 如果在超时期限内再次触发事件,则触发您的双击消息,否则调用单击处理程序。这是一些示例代码(编辑:最初在这里找到):
/// <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);
另一种选择是将 MouseBinding 添加到 StackElement 上的 InputBindings,然后添加一个由 MouseBinding 激活的 CommandBinding。总的来说,这比基于事件的机制更好,因为它避免了强引用引起的内存泄漏问题。它还提供了命令逻辑与表示的分离。
话虽如此,它并不那么直截了当,并且附加到事件中是一条很好的捷径。
不用说,让你的stackpanel背景至少是透明的,否则当你点击“背景”时它不会被鼠标点击命中测试捕捉到。命中检测会跳过空背景。
我有一个类似的问题(响应单击事件并在双击事件的情况下做额外的工作)。我这样解决了这个问题:
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 = 双击