我目前正在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资源管理器:
Google Chrome:
Adobe Acrobat:
Microsoft Edge:
(相同的图标,但DragDropEffects可能设置为None)
所以我的结论是必须有一个共同的窗口控制,但它在哪里?所有这些公司都没有办法巧妙地构建完全相同的设计和功能!
任何帮助将不胜感激!
奖励问题:显然在Windows 10中,您不允许拖放到以管理员身份运行的程序,但Chrome绝对允许您这样做。您可以将Chrome作为管理员运行,并将文件拖到其上,而不会出现任何问题。谷歌使用什么魔力绕过这个安全功能?我想要实现它,我的控件可能会在以管理员身份运行的程序中使用。
答案 0 :(得分:1)
标准的方法是委托Shell提供的drop icon render DragDropHelper COM Object。
它允许应用程序协商图像和图标显示。在您的情况下,资源管理器已使用IDragSourceHelper
进行拖动图标协商,因此您所要做的就是将放置事件委托给IDropTargetHelper
公开的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版本基本相同,只有很小的改动:
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);
}
参考文献: