在Windows应用程序开发中,实现文件的拖放操作是一个常见的需求。特别是在处理来自外部设备或服务器的大文件时,传统的拖放方法可能会因为文件下载速度慢而导致操作被取消。本文将介绍一种优化方法,通过实现一个自定义的拖放助手类来提高操作的效率和用户体验。
作者开发了一个Windows应用程序,该程序可以在ListView中显示外部设备上的文件。需求是允许用户通过拖放操作将文件从设备移动到本地机器。最初,作者尝试在调用ListView_ItemDrag事件的DoDragDrop方法之前,下载所有选定的文件。这种方法对于一两个小文件是有效的,但对于更多或更大的文件则不适用。因为当用户按下鼠标键时,文件下载速度变慢,Windows可能会取消拖放操作。
首先,需要创建一个名为FileDragDropHelper的类,该类继承自System.Windows.Forms.DataObject。接下来,需要重写GetDataPresent方法。在这个方法中,不要忘记调用基类的GetDataPresent方法。
public class FileDragDropHelper : DataObject
{
private int _downloadIndex;
private readonly Action _downloadAction;
public FileDragDropHelper(Action downloadAction)
{
if (downloadAction == null)
throw new ArgumentNullException("downloadAction");
_downloadAction = downloadAction;
}
public override bool GetDataPresent(string format)
{
StringCollection fileDropList = GetFileDropList();
if (fileDropList.Count > _downloadIndex)
{
string fileName = Path.GetFileName(fileDropList[_downloadIndex]);
if (!string.IsNullOrEmpty(fileName))
{
_downloadAction(fileDropList[_downloadIndex]);
_downloadIndex++;
}
}
return base.GetDataPresent(format);
}
}
第三步是使用新的拖放助手。在Windows表单中添加一个ListView控件,并用列表项填充它。在事件处理器中,遍历选定的ListView项,并将项文本填充到一个泛型字典中,其中键是临时文件夹中的目标文件,值是源Uri。对于拖放操作,必须指定目标文件存储在临时文件夹中。此外,还需要在StringCollection对象中填充一些临时文件。
private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
if (listView1.SelectedItems.Count == 0)
return;
StringCollection temporaryFiles = new StringCollection();
IDictionary sourceFiles = new Dictionary(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;
string targetFilePath = Path.Combine(Path.GetTempPath(), fileName);
temporaryFiles.Add(targetFilePath);
sourceFiles.Add(targetFilePath, item.Text);
}
FileDragDropHelper data = new FileDragDropHelper(file =>
{
KeyValuePair filePair = sourceFiles.FirstOrDefault(fi => string.Equals(fi.Key, file));
if (string.IsNullOrWhiteSpace(filePair.Key) || string.IsNullOrWhiteSpace(filePair.Value))
return;
WebRequest request = WebRequest.CreateDefault(new Uri(filePair.Value));
using (WebResponse response = request.GetResponse())
{
using (Stream readStream = response.GetResponseStream())
{
if (readStream == null || !readStream.CanRead)
return;
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);
});
}