【问题标题】:WPF handle drag and drop as well as left clickWPF处理拖放以及左键单击
【发布时间】:2012-10-09 14:19:02
【问题描述】:

我在让 DragDrop.DoDragDrop 与左键单击事件很好地配合时遇到了一些麻烦。

我的控件有几个可以拖动或左键访问的链接。

我目前订阅了预览鼠标移动事件,如果按下鼠标左键,我将在该事件中启动拖放事件。

在另一个回调中,我处理鼠标左键向下和向上事件以检查点击。有没有办法检查 DragDrop 是否真的发生了拖放事件?

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    查看this link drag drop in wpf explained end to end 并向下滚动到“检测拖放”部分

    此处插入的代码可防止博客丢失...

    来自 [http://msdn2.microsoft.com/en-us/library/aa289508(vs.71).aspx] 以下是典型拖放操作中的事件序列:

    通过调用源代码管理的 DoDragDrop 方法来启动拖动。

    DoDragDrop 方法有两个参数: data,指定要传递的数据 allowedEffects,指定允许哪些操作(复制和/或移动)

    会自动创建一个新的 DataObject 对象。 这反过来会引发 GiveFeedback 事件。在大多数情况下,您无需担心 GiveFeedback 事件,但如果您想在拖动过程中显示自定义鼠标指针,您可以在此处添加代码。

    任何将 AllowDrop 属性设置为 True 的控件都是潜在的放置目标。 AllowDrop 属性可以在设计时在“属性”窗口中设置,也可以在 Form_Load 事件中以编程方式设置。

    当鼠标经过每个控件时,会引发该控件的 DragEnter 事件。 GetDataPresent 方法用于确保数据的格式适合目标控件,Effect 属性用于显示适当的鼠标指针。

    如果用户在有效的放置目标上释放鼠标按钮,则会引发 DragDrop 事件。 DragDrop 事件处理程序中的代码从 DataObject 对象中提取数据并将其显示在目标控件中。

    检测拖放

    在调用 DoDragDrop 之前,我们必须检测源上的鼠标拖动操作...鼠标拖动通常是 MouseLeftButtonDown + MouseMove(在 MouseLeftButton 上升之前)。

    所以,我们的拖放源控件需要订阅这两个事件:

    void Window1_Loaded(object sender, RoutedEventArgs e)
    {
        this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
        this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
    }
    

    为防止在用户意外拖动的情况下启动错误的拖放操作,您可以使用

    SystemParameters.MinimumHorizo​​ntalDragDistance 和 SystemParameters.MinimumVerticalDragDistance

    一种方法是在 MouseLeftButtonDown 上,记录起始位置并在 onMouseMove 上检查鼠标是否移动得足够远..

    void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed && !IsDragging)
        {
            Point position = e.GetPosition(null);
    
            if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
                    Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
            {
                StartDrag(e); 
    
            }
        }   
    }
    
    void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _startPoint = e.GetPosition(null);
    }
    

    它是一个阻力..现在是什么?

    数据!您需要在拖动时找出鼠标下方的内容。 我将省略采取简单的方法并假设触发 MouseMove 的人就是我想要拖动的东西.. 所以看看 MouseEventArgs.OriginalSource.. [或者你可以使用 VisualTreeHelper 做一些 2D HitTesting .. 在这篇文章的第 3 部分将尝试引导您完成列表框的命中测试——这是我遇到的另一个常见场景。

    一旦有了要拖动的对象,您就需要将要发送的内容打包到描述您正在传递的数据的 DataObject 中。 DataObject 是将通用数据(以可扩展格式标识)推送到拖放中的包装器。只要源和目标都理解格式,您将被设置。因此,DataObject 有几个有趣的方法:

    SetData ( Type format, object data ) /// 格式是您传递当天的“格式”(例如 Formats.Text、Formats.Image 等),您可以传递任何自定义类型。

    GetDataPresent(Type format) /// 是放置目标用来查询和提取数据的..如果是它可以处理的类型,它会调用GetData()并处理它..

    这里没有太多有趣的东西。在示例中,我只是将我的数据硬编码为字符串类型...这样可以更轻松地粘贴到外部容器(例如 Word,您可以使用它来测试这部分写的)。我必须强调拖放应该是关于数据的...... 在拖放操作期间提供视觉反馈..

    在调用 DoDragDrop () 之前,我们需要围绕我们想要提供的反馈和 d&d 的“范围”做出一些“选择”。

    我们是否希望在进行拖动操作时显示自定义光标?如果我们想要一个游标,它应该是什么?

    我们想拖多远?在应用程序内还是跨 Windows 应用程序?

    最简单的场景:没有自定义光标,我们希望它可以跨应用拖动:

    如果你不想要一个花哨的光标,你就完了!!你可以直接调用DoDragDrop ...

    private void StartDrag(MouseEventArgs e)
    {
        IsDragging = true;
        DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
        DragDropEffects de = DragDrop.DoDragDrop(this.DragSource, data, DragDropEffects.Move);
        IsDragging = false;
    }
    

    注意:此代码允许您跨进程拖放,它使用默认的操作系统反馈(例如 + 表示复制)..

    【讨论】:

    • 5 年后我得到了一个没有任何解释的反对票,愚蠢的系统允许它。
    【解决方案2】:

    有 Drag Over/Enter/Leave Attached 事件 您可以在拖动的 UIElement 上订阅这些(或一个)事件的方法,并查看是否发生拖动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-11
      • 2011-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      相关资源
      最近更新 更多