【问题标题】:How to implement the common "Drag and Drop" icon in WinFormsWinForms中常见的“拖放”图标如何实现
【发布时间】:2017-11-11 23:14:29
【问题描述】:

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

简而言之,对于面板上的 DragEnter 和 DragDrop 事件,我的代码目前看起来像这样(删除了错误处理):

    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 图标,但我能得到的只是这个东西:

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

Windows 资源管理器:

谷歌浏览器:

Adobe Acrobat:

Microsoft Edge:

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

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

任何帮助将不胜感激!

奖励问题:显然,在 Windows 10 中,您不允许拖放到以管理员身份运行的程序上,但 Chrome 绝对允许您这样做。您可以以管理员身份运行 Chrome 并将文件拖到其上,没有任何问题。谷歌用了什么魔法绕过这个安全功能?我想实现它,并且我的控件可能会在以管理员身份运行的程序中使用。

【问题讨论】:

    标签: c# winforms file drag-and-drop


    【解决方案1】:

    执行此操作的标准方法是委托 Shell 提供的拖放图标渲染DragDropHelper COM Object

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

    互操作:

    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 版本基本相同,略有改动:

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

    参考资料:

    【讨论】:

      猜你喜欢
      • 2011-04-23
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-24
      相关资源
      最近更新 更多