【问题标题】:(Invoke) Cannot access a disposed object(调用)无法访问已处置的对象
【发布时间】:2020-02-05 05:38:46
【问题描述】:

我正在尝试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)

这是导致错误的特定行:

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();
    }

【问题讨论】:

  • “我试图检查 formMain 是否真的使用 this.IsDisposed 进行了处理” - 你在哪里检查的?在else?还是在你之前Invoke
  • @John 我在这两种情况下都试过了,但都没有帮助。

标签: c# winforms async-await delegates


【解决方案1】:

这里有一个很好的老式竞态条件

if (!canceller.IsCancellationRequested)

progressBar.Value = val; 

您可以在后者之前进行最终检查,它会缩短窗口但不会减轻它。

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

并且/或者您可以将 Value = val 更新包装在 trycatchObjectDisposedException 并注销

【讨论】:

  • 恐怕第一个建议没有帮助。至于后者,我知道我可以做到,但感觉像是在逃避,所以我想知道是否有适当的解决方案,但我开始认为没有。
  • @root 这个栏的更新速度有多快?
  • 我不知道如何回答,但每次触发TransferProgressChanged 时都会更新。
  • @root 我很惊讶if (!canceller.IsCancellationRequested) progressBar.Value = val; 没有帮助,但是如果消息泵被破坏它可能不会。无论哪种方式,你都不能保证它不会抛出,除非你保持表单打开直到你确定一切都赶上了
猜你喜欢
  • 2011-10-23
  • 2011-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多