(Invoke) Невозможно получить доступ к удаленному объекту - PullRequest
0 голосов
/ 05 февраля 2020

Я пробовал библиотеку FileTransferManager , которая используется для передачи файлов / папок. Когда я закрываю форму во время выполнения копии , иногда , я получаю эту ошибку:

Невозможно получить доступ к удаленному объекту. Имя объекта: 'formMain'.

И странная часть, как я упоминал ранее, я не всегда получаю эту ошибку. Иногда форма закрывается без каких-либо проблем.

Я пытался проверить, действительно ли formMain утилизируется с использованием this.IsDisposed во время возникновения ошибки, но всегда возвращает false. Я даже пытался поставить эту проверку в делегате, но это не помогло.

Вот StackTrace:

   at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
   at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
   at DirCopyTest.formMain.SetProgressBarValue(ProgressBar progressBar, Int32 val) in C:\Users\me\Documents\Visual Studio 2019\Projects\FileTransferManagerDemo\formMain.cs:line 73
   at DirCopyTest.formMain.TransferProgressChanged(TransferProgress tp) in C:\Users\me\Documents\Visual Studio 2019\Projects\FileTransferManagerDemo\formMain.cs:line 60
   at IOExtensions.FileTransferManager.<>c__DisplayClass7_0.<CopyFileWithProgress>b__0(Int64 size, Int64 transferred, Int64 streamSize, Int64 bytesTransferred, UInt32 number, CopyProgressCallbackReason reason, IntPtr file, IntPtr destinationFile, IntPtr data)

Это указанная строка c, которая вызывает ошибку:

Invoke(new SetProgressBarCallback(SetProgressBarValue), new object[] { progressBar, val });

А вот полный код:

    CancellationTokenSource canceller;

    private async void buttonCopy_Click(object sender, EventArgs e)
    {
        canceller = new CancellationTokenSource();
        Action<TransferProgress> progress = new Action<TransferProgress>(TransferProgressChanged);

        await FileTransferManager.CopyWithProgressAsync(source, destination, progress, canceller.Token, false, true);
    }

    void TransferProgressChanged(TransferProgress tp)
    {
        if (!canceller.IsCancellationRequested)
           SetProgressBarValue(progressBar1, (int)tp.Percentage);
    }

    delegate void SetProgressBarCallback(ProgressBar progressBar, int val);

    private void SetProgressBarValue(ProgressBar progressBar, int val)
    {
        if (progressBar.InvokeRequired)
            Invoke(new SetProgressBarCallback(SetProgressBarValue), new object[] { progressBar, val });
        else
            progressBar.Value = val;  
    }

    private void formMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        canceller.Cancel();
    }

1 Ответ

1 голос
/ 05 февраля 2020

То, что у вас есть, это хорошее старомодное состояние гонки между

if (!canceller.IsCancellationRequested)

и

progressBar.Value = val; 

Вы можете сделать окончательную проверку перед самым позже это сократит окно, но не уменьшит его.

if (!canceller.IsCancellationRequested)
   progressBar.Value = val;  

И / или вы можете просто обернуть обновление Value = val в try и catch в ObjectDisposedException и списать его

...