65.9K
CodeProject 正在变化。 阅读更多。
Home

异步拖放或从外部服务器/设备拖放

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2011年11月19日

CPOL

2分钟阅读

viewsIcon

22570

downloadIcon

487

从外部服务器或设备异步拖放文件。

引言

本文介绍如何从 Windows 应用程序中的 ListView 拖动来自外部设备或服务器的文件,这些文件未存储在可访问的计算机上。 它提供了一个类,该类中的文件在拖放操作时首先下载,然后再移动。

背景

我编写了一个 Windows 应用程序,它在 ListView 中显示外部设备上的文件。 要求是将文件通过拖放从设备移动到本地计算机。 我的第一次尝试是,在 ListView_ItemDrag 事件中调用 DoDragDrop 方法之前,从设备下载所有选定的文件。 对于一两个小文件来说,这是成功的,但对于更多或更大的文件来说,则不然。 在移动较大或更多文件时,下载速度比用户按下鼠标键的速度慢。 在这种情况下,拖放操作被 Windows 取消。

我在网上找到了两个使用大量 COMInterop 代码的示例。 我认为这必须更容易。

Using the Code

首先,编写一个像我的 FileDragDropHelper 这样的类。 该调用必须继承自 System.Windows.Forms.DataObject。 下一步,重写 GetDataPresent 方法。 请不要忘记在您的操作之后调用 base 方法 GetDataPresent

public class FileDragDropHelper : DataObject
{
    private int _downloadIndex;
    private readonly Action<string> _downloadAction;

    /// <summary>
    /// Initializes a new instance of the <see cref="FileDragDropHelper"/> class.
    /// </summary>
    /// <param name="downloadAction">The action delegate which handles 
    /// the download of the source file to the target path on local machine 
    /// or mapped server path.</param>
    public FileDragDropHelper(Action<string> downloadAction)
    {
        if (downloadAction == null)
            throw new ArgumentNullException("downloadAction");

            _downloadAction = downloadAction;
        }

    /// <summary>
    /// Determines whether data stored in this 
    /// <see cref="T:System.Windows.Forms.DataObject"/> is associated with, 
    /// or can be converted to, the specified format.
    /// </summary>
    /// <param name="format">The format to check for. 
    /// See <see cref="T:System.Windows.Forms.DataFormats"/> 
    /// for predefined formats.</param>      
    /// <returns>
    /// true if data stored in this <see cref="T:System.Windows.Forms.DataObject"/> 
    /// is associated with, or can be converted to, 
    /// the specified format; otherwise, false.
    /// </returns>

    public override bool GetDataPresent(string format)
        {
        StringCollection fileDropList = GetFileDropList();

        if (fileDropList.Count > _downloadIndex)
        {
            string fileName = Path.GetFileName(fileDropList[_downloadIndex]);

            if (string.IsNullOrEmpty(fileName))
                return false;
                    _downloadAction(fileDropList[_downloadIndex]);
                    _downloadIndex++;
            }

        return base.GetDataPresent(format);
        }
    }

第三步是使用我们的新拖放助手。 将 ListView 控件添加到您的 Windows Form 控件。 用您的列表项填充它。 在我的例子中,有两页网页。 将 ListViewItemDrag 事件与 Form-Designer 绑定。 在事件处理程序中,迭代选定的 ListView 项,并将项文本填充到泛型 Dictionary<string, string> 中,其中键是临时文件夹中的目标文件,值是源 Uri。 对于拖放操作,您必须指定目标文件存储在临时文件夹中。 此外,在 StringCollection 对象中填充一些临时 文件。

private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
    if(listView1.SelectedItems.Count == 0)

        return;

StringCollection temporaryFiles = new StringCollection();

IDictionary<string, string> sourceFiles = 
    new Dictionary<string, string>(listView1.SelectedItems.Count);

foreach (ListViewItem item in listView1.SelectedItems)
{
    if (string.IsNullOrWhiteSpace(item.Text))
        continue;
    string fileName = Path.GetFileName(item.Text);

    if(string.IsNullOrWhiteSpace(fileName))
        continue;

    // Create a temporary file with the source file name in the temp folder.
    // Also required for the Windows Drag 'n Drop engine.
    string targetFilePath = Path.Combine(Path.GetTempPath(), fileName);

    temporaryFiles.Add(targetFilePath);

    // Required! 
    // Add the source file to the source files list.
    // The source files list is needed for file download.

    sourceFiles.Add(targetFilePath, item.Text);
}

FileDragDropHelper data = new FileDragDropHelper(file =>
{
    // This lamda expression is equals with a method MethodName
    // (string file) {// do something}
    KeyValuePair<string, string> filePair = sourceFiles.FirstOrDefault
                (fi => string.Equals(fi.Key, file));

    if (string.IsNullOrWhiteSpace(filePair.Key) || 
        string.IsNullOrWhiteSpace(filePair.Value))
        return;

    // Do not download async in this async context
    WebRequest request = WebRequest.CreateDefault(new Uri(filePair.Value));

    using(WebResponse response = request.GetResponse())
        {
        // read response stream
        using(Stream readStream = response.GetResponseStream())
                {
            if (readStream == null || !readStream.CanRead)

                return;

            // write stream to file of the current temporary files
            using(FileStream writeStream = new FileStream
        (filePair.Key, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                        {
                byte[] buffer = new byte[16384];

                for (int index = readStream.Read(buffer, 0, buffer.Length); 
        index > 0; index = readStream.Read(buffer, 0, buffer.Length))
                                    writeStream.Write(buffer, 0, index);
                        }
                    }
                }
            });

            data.SetFileDropList(temporaryFiles);

            DoDragDrop(data, DragDropEffects.Copy);
        }

关注点

FileDragDropHelper 类中的 GetDataPresent 方法是成功的关键。

历史

  • 2011 年 11 月 19 日:首次发布
© . All rights reserved.