【发布时间】:2014-05-01 17:55:43
【问题描述】:
我正在开发一个 dragScrollViewer,在 OnPreviewMouseLeftButtonUp 函数中使用“e.Handled=true”时遇到了一些奇怪的问题。
在鼠标左键下,不知道用户是想“点击”下方还是想用鼠标“滑动/拖动”。如果他已经开始“滑动/拖动”,我想“吃/取消”鼠标点击。
这应该很简单...... OnPreviewMouseLeftButtonUp 函数中的“e.Handled = true”应该会阻止鼠标点击点击更高级别的按钮(鼠标下方)。然而,这会产生一个非常奇怪的行为......点击(及其坐标)被存储并在稍后(用户下次点击时)抛出。
我不知道我的代码是否有问题,或者 WPF 路由事件框架中是否存在错误...是否有人能够重现该问题? (为了让代码更简单,我把所有拖拽的代码都去掉了)
如何重现问题:
- 在 Visual Studio 中创建一个干净的项目 WPF 项目。
- 插入示例源代码 DragScroller.cs/MainWindow.xaml/MainWindow.xaml.cs
- 编译并单击按钮 - 结果:控制台显示“单击了内部 dragScroller 按钮”
- 接下来单击一个按钮并开始滑动(仍停留在按钮区域内 - 结果:鼠标单击被取消
- 现在单击“外部 dragScroller” - 结果:控制台写入“内部 dragScroller 按钮单击”(这是存储的“鼠标”单击)
如果取消单击的决定是在用户释放鼠标按钮时首先知道的,是否有更好的方法来取消鼠标单击?
DragScroller.cs:
using System.Windows.Controls;
using System.Windows.Input;
namespace dragScroller
{
public class DragScrollViewer : ScrollViewer
{
private bool mouseDown;
private bool isDragging;
private int dragMoveCount;
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
CancelMouseDrag();
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
dragMoveCount = 0;
mouseDown = true;
}
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
dragMoveCount++;
if (!mouseDown || isDragging || !(dragMoveCount > MoveTicksBeforeDrag)) return;
Cursor = Cursors.ScrollAll;
isDragging = true;
}
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonUp(e);
if (isDragging && dragMoveCount > MoveTicksBeforeDrag)
{
e.Handled = true;// Calling e.Handled here, has an unwanted effect on the next "up" event
CancelMouseDrag();
}
dragMoveCount = 0;
Cursor = Cursors.Arrow;
}
private void CancelMouseDrag()
{
isDragging = false;
mouseDown = false;
Cursor = Cursors.Arrow;
dragMoveCount = 0;
}
private const double MoveTicksBeforeDrag = 5; //times to call previewMouseMove before starting to drag (else click)
}
}
MainWindows.xaml:
<Window x:Class="dragScroller.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dragScroller="clr-namespace:dragScroller"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Content="Outside dragScroller" Click="Button_Click" />
<dragScroller:DragScrollViewer x:Name="dragScroller" Friction="0.2" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Visible">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Button Content="Button #1" Grid.Column="0" Grid.Row="0" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #2" Grid.Column="1" Grid.Row="0" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #3" Grid.Column="2" Grid.Row="1" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #4" Grid.Column="3" Grid.Row="1" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #5" Grid.Column="4" Grid.Row="0" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #6" Grid.Column="5" Grid.Row="0" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #7" Grid.Column="6" Grid.Row="1" Click="Button_Click_Inside_DragScroller"></Button>
<Button Content="Button #8" Grid.Column="7" Grid.Row="1" Click="Button_Click_Inside_DragScroller"></Button>
</Grid>
</dragScroller:DragScrollViewer>
</StackPanel>
</Window>
MainWindows.xaml.cs:
namespace dragScroller
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Outside dragScroller button clicked");
}
private void Button_Click_Inside_DragScroller(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Inside dragScroller button clicked");
}
}
}
【问题讨论】:
标签: wpf wpf-controls routed-events