如何实现常见的“拖放”操作? WinForms中的图标 [英] How to implement the common "Drag and Drop" icon in WinForms

查看:75
本文介绍了如何实现常见的“拖放”操作? WinForms中的图标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在用C#设计一个简单的WinForms UserControl,用户可以在其中将excel文件拖放到面板上,而不用浏览该文件。从技术上讲,我可以使用它,但是它非常粗糙。

I'm currently designing a simple WinForms UserControl in C# where a user can drag and drop an excel file onto a panel instead of browsing for the file. I have it technically working, but it's very crude.

简而言之,当前我的代码在面板上的DragEnter和DragDrop事件中看起来是这样的(已删除错误处理):

In short, my code currently looks like this for the DragEnter and DragDrop events on the panel (removed error handling):

    private void dragPanel_DragEnter(object sender, DragEventArgs e)
    {
        var filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
        if (Path.GetExtension(filenames[0]) == ".xlsx") e.Effect = DragDropEffects.All;
        else e.Effect = DragDropEffects.None;
    }

    private void dragPanel_DragDrop(object sender, DragEventArgs e)
    {
        var filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
        string filename = filenames[0];
        // Do stuff
    }

我正在尝试获取Excel图标在我拖动文件时显示,但是我能得到的就是这个东西:

I'm trying to get the Excel icon to show up as I drag the file, but all I can get is this thing:

我在网上看过的所有地方(大多在这个论坛上)都说过,如果我想显示特定的图标,则需要实现自己的自定义光标,但是老实说我不相信。我截取了来自不同公司的多个应用程序的屏幕快照,全部使用了完全相同的控件(这只是其中的一个子集)。请注意,它们都不是光标,图标仅跟随光标:

Anywhere I've looked online (mostly on this forum) has said I need to implement my own custom cursor if I want a specific icon to show up, but I honestly don't believe that. I took screenshots of multiple applications from different companies all using the exact same control (this is just a subset). Note that none of them are even cursors, the icons just follow the cursor:

Windows资源管理器:

Google Chrome浏览器:

Adob​​e Acrobat:

Microsoft Edge:

(相同的图标,但DragDropEffects可能设置为None)

(Same icon, but DragDropEffects are likely set to None)

所以我的结论是必须有一个通用的Windows控件,但是它在哪里?所有这些公司都不可能巧合地构建完全相同的设计和功能!

So my conclusion is there must be a common windows control for this, but where is it? There's no way all of these companies just coincidentally built the exact same design and functionality!

任何帮助将不胜感激!

奖金问题:显然,在Windows 10中,您不允许拖放到以管理员身份运行的程序,但是Chrome绝对可以让您执行此操作。您可以以管理员身份运行Chrome并将文件拖到其上,而不会出现任何问题。 Google使用了什么魔术来绕过此安全功能?我想实现它,并且我的控件也可以在以admin身份运行的程序中使用。

Bonus Question: Apparently in Windows 10 you're not allowed to drag-and-drop onto a program that's running as Administrator, however Chrome definitely lets you do this. You can run Chrome as Admin and drag a file onto it without any issue. What magic did Google use to bypass this security feature? I'd like to implement it as well as my control could potentially be used inside a program running as admin.

推荐答案

标准方式要做的就是委托放置图标渲染 DragDropHelper COM对象

Standard way to do that is to delegate drop icon rendering DragDropHelper COM Object provided by Shell.

它允许应用程序协商要显示的图像和图标。在您的情况下,资源管理器已经使用 IDragSourceHelper 进行拖动图标协商,因此您要做的就是将放置事件委托给 IDropTargetHelper DragDropHelper 公开:

It allows application to negotiate image and icon to be displayed. In your case, Explorer already uses IDragSourceHelper for drag icon negotiation, so all you have to do is to delegate drop events to IDropTargetHelper exposed by DragDropHelper:

互操作:

using IDataObject_Com = System.Runtime.InteropServices.ComTypes.IDataObject;

[StructLayout(LayoutKind.Sequential)]
public struct Win32Point
{
    public int x;
    public int y;
}

[ComImport]
[Guid("4657278A-411B-11d2-839A-00C04FD918D0")]
public class DragDropHelper { }

[ComVisible(true)]
[ComImport]
[Guid("4657278B-411B-11D2-839A-00C04FD918D0")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDropTargetHelper
{
    void DragEnter(
        [In] IntPtr hwndTarget,
        [In, MarshalAs(UnmanagedType.Interface)] IDataObject_Com dataObject,
        [In] ref Win32Point pt,
        [In] int effect);
    void DragLeave();

    void DragOver(
        [In] ref Win32Point pt,
        [In] int effect);

    void Drop(
        [In, MarshalAs(UnmanagedType.Interface)] IDataObject_Com dataObject,
        [In] ref Win32Point pt,
        [In] int effect);

    void Show(
        [In] bool show);
}

表格:

private IDropTargetHelper ddHelper = (IDropTargetHelper)new DragDropHelper();

private void Form1_DragDrop(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Copy;
    Point p = Cursor.Position;
    Win32Point wp;
    wp.x = p.X;
    wp.y = p.Y;

    ddHelper.Drop(e.Data as IDataObject_Com, ref wp, (int)e.Effect);
}

private void Form1_DragEnter(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Copy;
    Point p = Cursor.Position;
    Win32Point wp;
    wp.x = p.X;
    wp.y = p.Y;

    ddHelper.DragEnter(this.Handle, e.Data as IDataObject_Com, ref wp, (int)e.Effect);
}

private void Form1_DragLeave(object sender, EventArgs e)
{
    ddHelper.DragLeave();
}

private void Form1_DragOver(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Copy;
    Point p = Cursor.Position;
    Win32Point wp;
    wp.x = p.X;
    wp.y = p.Y;

    ddHelper.DragOver(ref wp, (int)e.Effect);
}

WPF版本基本相同,只是稍有变化:

WPF Version is basically the same, with minor changes:

private void Window_DragEnter(object sender, DragEventArgs e)
{
    e.Effects = DragDropEffects.Copy;
    e.Handled = true;
    Point p = this.PointToScreen(e.GetPosition(this));
    Win32Point wp;
    wp.x = (int)p.X;
    wp.y = (int)p.Y;
    ddHelper.DragEnter(new WindowInteropHelper(this).Handle, e.Data as IDataObject_Com, ref wp, (int)e.Effects);
}

参考文献:

  • PInvoke on IDropTargetHelper
  • MSDN Blogs: Shell Style Drag and Drop in .NET (WPF and WinForms) - covers both source and target implementation.
  • Chrome / Chromium DragDrop Target Helper.

这篇关于如何实现常见的“拖放”操作? WinForms中的图标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆