перетащить в другой процесс - PullRequest
9 голосов
/ 10 января 2010

Я пытаюсь перетащить элемент в проводник.
Элемент должен привести к загрузке файла, поэтому я использовал пример, который я нашел в Интернете, для загрузки файла с помощью CustomDataObject, который вызывает событие, когда ему действительно нужен поток, а затем мое приложение выполняет тяжелую работу. поднимает и выполняет загрузку.
Он работал очень хорошо в аналогичной операции с буфером обмена.

Фактическая загрузка файла также вызывает некоторые изменения пользовательского интерфейса в моем приложении. В большинстве случаев на форме меняется «рабочий» значок, а также всплывающее окно в случае ошибки.

В операции с буфером обмена я просто использовал InvokeRequired и BeginInvoke, когда это необходимо, чтобы изменения в пользовательском интерфейсе происходили в основном потоке. В операции перетаскивания поток пользовательского интерфейса ожидает возврата из DoDragDrop, в то время как событие, вызываемое CustomDataObject, вызывается в другом потоке. Когда я пытаюсь вызвать BeginInvoke или Invoke, поток пользовательского интерфейса все еще ждет, и я не могу завершить удаление.

Существует ли какой-либо пример или рекомендуемый лучший способ разрешить перетаскивание между приложениями при одновременном доступе к пользовательскому интерфейсу исходного приложения?

UPDATE

здесь - это оригинальная статья CodeProject с DataObjectEx, которую я модифицировал для собственного использования. Я просто изменил метод GetFileContents для вызова виртуального метода, который возвращает Stream, содержащий данные файла, унаследованные от класса, и переопределил этот виртуальный метод для получения файла из Интернета. Проблема возникла, когда я хотел что-то изменить в пользовательском интерфейсе при получении файла. Как я уже говорил ранее - основной поток пользовательского интерфейса все еще «застрял» при вызове метода DoDragDrop, поэтому я не могу вовремя вызвать его, чтобы внести изменения в пользовательский интерфейс, необходимые рабочему потоку до и после загрузки файла.

Ответы [ 2 ]

1 голос
/ 11 января 2010

У меня была та же проблема, и я обнаружил, что System.Windows.Forms.Control.DoDragDrop проигнорировал реализацию моей формы COM-функции IAsyncOperation, вместо этого используя внутреннюю реализацию DataObject объекта WinForm для IDataObject. К сожалению, класс DataObject WinForm не реализует IAsyncOperation.

Таким образом, я использовал реализацию проекта VirtualFileDataObject для IAsyncOperation, IDataObject, вызывая VirtualFileDataObject.DoDragDrop вместо Control.DoDragDrop. Я установил VirtualFileDataObject.FileDescriptor.StreamContents для делегата, где я вызываю поток пользовательского интерфейса, чтобы сообщить о прогрессе при загрузке файла.

1 голос
/ 11 января 2010

Если это стандартное приложение WinForms, то все, что вам действительно нужно сделать в своем приложении, это добавить обработчики событий в форму для DragEnter и DragDrop.

Внутри DragEnter вы захотите проверить тип объекта, чтобы убедиться, что это имя файла:

private void MyForm_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
        if (files != null)
        {
            // Do additional checks here if needed, like check extensions
            e.Effect = DragDropEffects.Copy;
            return;
        }
    }

    e.Effect = DragDropEffects.None;
}

Затем в вашем обработчике DragDrop я просто сохраню имена файлов, а затем активирую таймер. Это позволяет DragDrop немедленно вернуться, чтобы другое приложение (в вашем примере, Windows Explorer) не зависало при выполнении какой-либо обработки файла, которая может занять некоторое время. Drag Source не вернет , пока DragDrop не завершится.

private void MyForm_DragDrop(object sender, DragEventArgs e)
{
    string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
    if (files != null)
    {
        _filesToProcess.Text = files[0];  // Assuming this is declared at the Form level

        // Schedule a timer to fire in a few miliseconds as a simple asynchronous method
        _DragDropTimer.Interval = 50;
        _DragDropTimer.Enabled = true;
        _DragDropTimer.Start();
        Activate();  // Activates the form and gives it focus
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...