Introduction
This article is about item dragging from a ListView
in Windows application with files from an external device or Server, which are not stored on an accessible machine. It provides a class, which files on the drag 'n drop operation downloaded at first, before they are moved.
Background
I have written a Windows application which displayed in a ListView
files on an external device. The requirement was, moves the files by Drag ‘n Drop from device to the local machine. My first try was, download all selected files from device, before calling the DoDragDrop
method in the ListView_ItemDrag
event. That was successful for one or two small files, but not for more or larger files. On moving of larger or more files, the download was slower as the user has pressed the mouse key. In this case, the Drag ‘n Drop operation was cancelled by Windows.
I have found in the web two examples which work with a lot of COMInterop code. I thought that must be easier.
Using the Code
At first, write a class like my FileDragDropHelper
. The call must be inherited from System.Windows.Forms.DataObject
. As the next step, override the method GetDataPresent
. Please don’t forget to call the base
method GetDataPresent
after your action.
public class FileDragDropHelper : DataObject
{
private int _downloadIndex;
private readonly Action<string> _downloadAction;
public FileDragDropHelper(Action<string> 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))
return false;
_downloadAction(fileDropList[_downloadIndex]);
_downloadIndex++;
}
return base.GetDataPresent(format);
}
}
The 3rd step is the using of our new drag drop helper. Add a ListView
control to your Windows Form control. Fill that with your list item. In my case, there are two web pages. Bind the ItemDrag
event of the ListView
with the Form-Designer. In the event handler, iterate over the selected ListView
items and fill the item text into a generic Dictionary<string, string>,
where the key is the target file in a temporary folder and the value is the source Uri. For the drag-drop operation you must specify that the target file is stored in a temporary folder. In addition, fill some temporary files in a StringCollection
object.
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;
string targetFilePath = Path.Combine(Path.GetTempPath(), fileName);
temporaryFiles.Add(targetFilePath);
sourceFiles.Add(targetFilePath, item.Text);
}
FileDragDropHelper data = new FileDragDropHelper(file =>
{
KeyValuePair<string, string> 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);
}
Points of Interest
The GetDataPresent
method in the class FileDragDropHelper
is the key for success.
History
- 19th November, 2011: Initial post