如何取消鼠标左键单击按钮释放(预览...向上)

时间:2014-05-01 17:55:43

标签: wpf wpf-controls routed-events

我正在开发一个dragScrollViewer,并且在OnPreviewMouseLeftButtonUp函数中使用“e.Handled = true”时会遇到一些奇怪的事情。

在左边的mousedown,不知道用户是想在下面“点击”还是想要用鼠标“滑动/拖动”。如果他已经开始“滑动/拖动”,我想“吃掉/取消”鼠标点击。

这应该非常简单...... OnPreviewMouseLeftButtonUp函数中的“e.Handled = true”应该停止鼠标点击更高级别按钮(鼠标下方)。然而,这会产生一种非常奇怪的行为......点击(及其坐标)会被存储并在以后抛出(下次用户点击)。

我不知道我的代码是否有问题,或者WPF路由事件框架中是否存在错误......是否有人能够重现该问题? (为了使代码更简单,我删除了所有拖动代码)

如何重现问题:

  1. 在Visual Studio中创建一个干净的项目WPF项目。
  2. 插入示例源代码DragScroller.cs / MainWindow.xaml / MainWindow.xaml.cs
  3. 编译并单击按钮 - 结果:控制台写入“单击内部拖动滚轮按钮”
  4. 然后单击按钮并开始滑动(仍然停留在按钮区域内 - 结果:鼠标单击被取消
  5. 现在点击“Outside dragScroller” - 结果:控制台写入“Inside dragScroller button clicked”(这是存储的“鼠标”点击)
  6. 如果在用户释放鼠标按钮时首先知道取消点击的决定,是否有更好的方法取消鼠标点击?


    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");
        }
      }
    }
    

1 个答案:

答案 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;
    }
希望它有所帮助。