我正在开发一个dragScrollViewer,并且在OnPreviewMouseLeftButtonUp函数中使用“e.Handled = true”时会遇到一些奇怪的事情。
在左边的mousedown,不知道用户是想在下面“点击”还是想要用鼠标“滑动/拖动”。如果他已经开始“滑动/拖动”,我想“吃掉/取消”鼠标点击。
这应该非常简单...... OnPreviewMouseLeftButtonUp函数中的“e.Handled = true”应该停止鼠标点击更高级别按钮(鼠标下方)。然而,这会产生一种非常奇怪的行为......点击(及其坐标)会被存储并在以后抛出(下次用户点击)。
我不知道我的代码是否有问题,或者WPF路由事件框架中是否存在错误......是否有人能够重现该问题? (为了使代码更简单,我删除了所有拖动代码)
如何重现问题:
如果在用户释放鼠标按钮时首先知道取消点击的决定,是否有更好的方法取消鼠标点击?
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)
}
}
<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>
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");
}
}
}
答案 0 :(得分:1)
我修改了OnPreviewMouseLeftButtonUp方法并设法修复此行为。 调用错误的事件处理程序,因为该按钮仍处于焦点位置。 如果您将焦点移回主窗口,它应该按预期工作:
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
var x = e.Source as Button;
if (x != null)
{
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(x), Application.Current.MainWindow);
}
CancelMouseDrag();
}
dragMoveCount = 0;
Cursor = Cursors.Arrow;
}
希望它有所帮助。