[英]C# WPF - DragDrop a remote file to Windows Explorer
I am working on a WPF application which shows a list of files stored on a remote server (just like dropbox).我正在开发一个 WPF 应用程序,该应用程序显示存储在远程服务器上的文件列表(就像保管箱一样)。 I want users to drag and drop them onto desktop or any folder.
我希望用户将它们拖放到桌面或任何文件夹上。 There are many questions posted related to this but none of them really give a complete solution.
发布了许多与此相关的问题,但没有一个真正给出完整的解决方案。
Here is the complete code I am using https://github.com/dotriz/VirtualDragDrop/这是我使用的完整代码https://github.com/dotriz/VirtualDragDrop/
This is a very simple task if file is stored on local system, but here file is on a remote server and need to be downloaded first.如果文件存储在本地系统上,这是一个非常简单的任务,但这里的文件在远程服务器上,需要先下载。
The only article related to this, is 13 years old posted here https://dlaa.me/blog/post/9923072 .与此相关的唯一一篇文章是 13 岁发布在这里https://dlaa.me/blog/post/9923072 。 It has few issues too, like
它也有一些问题,比如
Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC)
FORMATETC 结构无效(HRESULT 异常:0x80040064 (DV_E_FORMATETC)
Here is the code used on MouseDown event of a label.这是用于 label 的 MouseDown 事件的代码。 It uses VirtualFileDataObject class from the link given above
它使用上面给出的链接中的VirtualFileDataObject class
private void VirtualFile2_MouseButtonDown(object sender, MouseButtonEventArgs e)
{
var virtualFileDataObject = new VirtualFileDataObject();
virtualFileDataObject.SetData(new VirtualFileDataObject.FileDescriptor[]
{
new VirtualFileDataObject.FileDescriptor
{
Name = "test.zip",
ChangeTimeUtc = DateTime.Now.AddDays(-1),
StreamContents = stream =>
{
using(var webClient = new WebClient())
{
var data = webClient.DownloadData("https://somesite.com/test.zip");
stream.Write(data, 0, data.Length);
}
}
},
});
DoDragDropOrClipboardSetDataObject(e.ChangedButton, VirtualFile2, virtualFileDataObject, DragDropEffects.Copy);
}
private static void DoDragDropOrClipboardSetDataObject(MouseButton button, DependencyObject dragSource, VirtualFileDataObject virtualFileDataObject, DragDropEffects allowedEffects)
{
try
{
VirtualFileDataObject.DoDragDrop(dragSource, virtualFileDataObject, allowedEffects);
}
catch (COMException)
{
// Failure; no way to recover
}
}
I can successfully use the provided reproduction program.我可以成功使用提供的复制程序。 It works at least on Windows 10, 11, x86 x64 in Release and Debug configuration, when ran without debugging it .
它至少适用于 Windows 10、11、x86 x64 在发布和调试配置中,在没有调试的情况下运行。
DV_E_FORMATETC (0x80040064 ) is just a standard error code that means the data object doesn't support the clipboard format that's requested. DV_E_FORMATETC (0x80040064) 只是一个标准错误代码,表示数据 object 不支持所请求的剪贴板格式。 This error is common in copy/paste, drag&drop and clipboard operations.
此错误在复制/粘贴、拖放和剪贴板操作中很常见。
What doesn't work at all is:根本不起作用的是:
void System.Runtime.InteropServices.ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium)
while running in Debug mode.void System.Runtime.InteropServices.ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium)
中。 I don't think you can debug a .NET program (with today tools) with breakpoints or exceptions being throw when in a DoDragDrop function call.我不认为您可以调试 .NET 程序(使用今天的工具),在DoDragDrop function调用中抛出断点或异常。
DoDragDrop
is a big modal loop that eats most messages sent to a window. DoDragDrop
是一个大的模态循环,它吃掉发送到 window 的大多数消息。 Unfortunately the .NET debugger facility or exception handler (in clr.dll) seems to also wait on this loop for some reason.不幸的是,.NET 调试器工具或异常处理程序(在 clr.dll 中)似乎也出于某种原因等待此循环。 So, hitting a breakpoint or handling an exception creates a hang in the program itself (and in the debugger too) that you can only break the dead lock by killing the debugged process the hard way (
taskkill /im myprocess.exe /f
command line for example).因此,打断点或处理异常会在程序本身(以及调试器)中创建一个挂起,您只能通过硬方式杀死被调试的进程来打破死锁(
taskkill /im myprocess.exe /f
命令行例如)。
So my recommendation is to:所以我的建议是:
avoid putting breakpoints in these portions of code避免在这些代码部分放置断点
wrap these functions in try/catch
block and use some non-intrusive trace mechanism, something like this:将这些函数包装在
try/catch
块中,并使用一些非侵入式跟踪机制,如下所示:
void System.Runtime.InteropServices.ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) { try {.... } catch(Exception ex) { Trace.WriteLine("GetData Error: " + ex); throw; // rethrow as is } }
EDIT: This answer is wrong编辑:这个答案是错误的
I can explain why the UI hangs and how to solve it.我可以解释为什么 UI 挂起以及如何解决它。 There are two IO operations inside VirtualFile2_MouseButtonDown which you perform in a blocking way.
VirtualFile2_MouseButtonDown 中有两个 IO 操作,您以阻塞方式执行。 This obviously blocks the UI thread until both operations finish.
这显然会阻塞 UI 线程,直到两个操作都完成。
private async void VirtualFile2_MouseButtonDown
private async void VirtualFile2_MouseButtonDown
This way, VirtualFile2_MouseButtonDown will return on the first IO operation and continuation tasks will be scheduled on the UI thread when the async IO operation is ready.这样,VirtualFile2_MouseButtonDown 将在第一个 IO 操作时返回,并且当异步 IO 操作准备好时,将在 UI 线程上安排继续任务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.