2
votes

In WinForms and other applications (e.g. Windows Notepad), you can drag and drop (e.g. a file) into the whole window – this includes the title bar and window borders.

In WPF, you can drag a file only into the window canvas – trying to drag it over the title bar or window borders results in the “no” cursor.

enter image description here

How can I make an ordinary WPF window (SingleBorderWindow WindowStyle, etc.) accept drag and drop into the whole window?

1

1 Answers

4
votes

The difference is that WPF is not calling the OS DragAcceptFiles API when you set AllowDrop="true". DragAcceptFiles registers the entire window as a drop target.

You'll need to pinvoke and have a small window procedure to handle the drop message.

Here's a small test program I made to allow the WPF window to accept the drop anywhere.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

     const int WM_DROPFILES = 0x233;

    [DllImport("shell32.dll")]
    static extern void DragAcceptFiles(IntPtr hwnd, bool fAccept);

    [DllImport("shell32.dll")]
    static extern uint DragQueryFile(IntPtr hDrop, uint iFile, [Out] StringBuilder filename, uint cch);

    [DllImport("shell32.dll")]
    static extern void DragFinish(IntPtr hDrop);


    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        var helper = new WindowInteropHelper(this);
        var hwnd = helper.Handle;

        HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
         source.AddHook(WndProc);

        DragAcceptFiles(hwnd, true);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_DROPFILES) 
        {
            handled = true;
            return HandleDropFiles(wParam);
        }

        return IntPtr.Zero;
    }

    private IntPtr HandleDropFiles(IntPtr hDrop)
    {
        this.info.Text = "Dropped!";

        const int MAX_PATH = 260;

        var count = DragQueryFile(hDrop, 0xFFFFFFFF, null, 0);

        for (uint i = 0; i < count; i++)
        {
            int size = (int) DragQueryFile(hDrop, i, null, 0);

            var filename = new StringBuilder(size + 1);
            DragQueryFile(hDrop, i, filename, MAX_PATH);

            Debug.WriteLine("Dropped: " + filename.ToString());
        }

        DragFinish(hDrop);

        return IntPtr.Zero;
    }
}