【问题标题】:How to handle arbitrary events during a drag and drop operation in WPF?如何在 WPF 中的拖放操作期间处理任意事件?
【发布时间】:2013-05-11 07:23:52
【问题描述】:

我想在拖放操作期间处理 OnMouseMove 或 MouseWheel 等事件。

但是,据我从this MSDN topic on Drag/Drop 得知,在拖放操作期间触发的唯一事件是 GiveFeedback、QueryContinueDrag、Drag Enter/Leave/Over 以及它们的 Preview* 对应事件。从本质上讲,处理这些事件可以让我获取鼠标位置,或者查看用户是否按下 Ctrl、Shift、Alt、Esc,或者按下或释放鼠标按钮之一。

不过,我想要的是在拖放操作期间处理其他事件,例如 MouseWheel。具体来说,我想做的是让用户滚动窗口的内容(使用鼠标滚轮),同时在窗口上拖动一些东西。我已经尝试为这些其他事件编写处理程序,包括冒泡和隧道版本,以及将它们附加到控制层次结构的各个级别,但据我所知,它们都没有触发。

我知道有一个部分解决方案(例如描述为here),当鼠标位置靠近窗口的顶部或底部时,您可以使用 DragOver 滚动窗口的内容。但这不是我想做的。

我遇到了一个article,这意味着可以在拖动操作期间处理(例如)OnMouseMove 事件。我这么说是因为文章中的代码是上述方法的变体,但它处理的是 OnMouseMove 而不是 DragOver。但是,我尝试采用这种方法,但仍然无法在拖动时触发 OnMouseMove 事件。我在下面添加了我的代码。它在 F# 中,所以我使用了来自 FSharpx 的 F# XAML type provider

MainWindow.xaml:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="500" Width="900">
    <DockPanel Name="panel1">
        <StatusBar Name="status1" DockPanel.Dock="Bottom">
            <TextBlock Name="statustext1" />
        </StatusBar>
    </DockPanel>
</Window>

程序.fs:

(* 
Added references: PresentationCore, PresentationFramework, System.Xaml, UIAutomationTypes, WindowsBase.
*)

// STAThread, DateTime
open System
// Application
open System.Windows
// TextBox
open System.Windows.Controls

// XAML type provider
open FSharpx

type MainWindow = XAML<"MainWindow.xaml">

type TextBox2 (status : TextBlock) as this =
    inherit TextBox () with
    member private this.preview_mouse_left_button_down (args : Input.MouseButtonEventArgs) = do
        this.CaptureMouse () |> ignore
        base.OnPreviewMouseLeftButtonDown args
// Fires while selecting text with the mouse, but not while dragging.
    member private this.preview_mouse_move (args : Input.MouseEventArgs) =
        if this.IsMouseCaptured then do status.Text <- sprintf "mouse move: %d" <| DateTime.Now.Ticks
        do base.OnPreviewMouseMove args
    member private this.preview_mouse_left_button_up (args : Input.MouseButtonEventArgs) = do
        if this.IsMouseCaptured then do this.ReleaseMouseCapture ()
        base.OnPreviewMouseLeftButtonUp args
    do
        this.PreviewMouseLeftButtonDown.Add this.preview_mouse_left_button_down
        this.PreviewMouseMove.Add this.preview_mouse_move
        this.PreviewMouseLeftButtonUp.Add this.preview_mouse_left_button_up

let load_window () =
    let win = MainWindow ()
    let t = new TextBox2 (win.statustext1)
    do
        t.TextWrapping <- TextWrapping.Wrap
        t.AcceptsReturn <- true
        t.Height <- Double.NaN
        win.panel1.Children.Add t |> ignore
    win.Root

[<STAThread>]
(new Application () ).Run(load_window () ) |> ignore

【问题讨论】:

    标签: wpf drag-and-drop


    【解决方案1】:

    我认为您可以使用 PreviewDragEnterPreviewDragOverDrop 更有效地做到这一点。我写了一个关于编写自己的拖放文本框的博客主题,它应该可以帮助你入门。您可以从那里添加滚动功能:

    http://xcalibur37.wordpress.com/2011/12/10/wpf-drag-and-drop-textbox-for-windows-explorer-files/

    代码:

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            // Initialize UI
            InitializeComponent();
    
            // Loaded event
            this.Loaded += delegate
                {
                    TextBox1.AllowDrop = true;
                    TextBox1.PreviewDragEnter += TextBox1PreviewDragEnter;
                    TextBox1.PreviewDragOver += TextBox1PreviewDragOver;
                    TextBox1.Drop += TextBox1DragDrop;
                };
        }
    
        /// <summary>
        /// We have to override this to allow drop functionality.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void TextBox1PreviewDragOver(object sender, DragEventArgs e)
        {
            e.Handled = true;
        }
    
        /// <summary>
        /// Evaluates the Data and performs the DragDropEffect
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox1PreviewDragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
        }
    
        /// <summary>
        /// The drop activity on the textbox.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox1DragDrop(object sender, DragEventArgs e)
        {
            // Get data object
            var dataObject = e.Data as DataObject;
    
            // Check for file list
            if (dataObject.ContainsFileDropList())
            {
                // Clear values
                TextBox1.Text = string.Empty;
    
                // Process file names
                StringCollection fileNames = dataObject.GetFileDropList();
                StringBuilder bd = new StringBuilder();
                foreach (var fileName in fileNames)
                {
                    bd.Append(fileName + "\n");
                }
    
                // Set text
                TextBox1.Text = bd.ToString();
            }
        }
    }
    

    博客主题为您提供每个部分的细分分析。

    【讨论】:

    • 感谢您对 Xcalibur 的回复。在这种情况下,我不必自己实现拖放功能,但下次我会记住您的回复。我希望做的是在拖动时处理除了 DragEnter/Over/Leave/Drop 事件之外的一些事件。换句话说,我想在拖动时处理一些像 MouseOver 这样的任意事件。但是,这些其他事件似乎在拖动操作期间根本不会触发。
    【解决方案2】:

    我知道这是一个老问题,但我必须做类似的事情,我的解决方案也适用于这个问题。我想我不妨在这里链接它以防万一。这不是最简单的解决方案,但效果很好。

    我最终通过 p/invoke 使用 hooks 在本地窗口消息被拖放操作消耗之前获取它们。通过使用 WH_MOUSE 钩子,我能够在没有 WPF 的 Mouse 和 DragDrop 事件的情况下拦截 WM_MOUSEMOVE 消息并跟踪鼠标。这应该适用于所有鼠标消息,包括 WM_MOUSEWHEEL。

    您可以查看我最终发布自己答案的问题。我包含了大部分源代码:
    WPF - Track mouse during Drag & Drop while AllowDrop = False

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多