为什么我会得到异常:InvalidOperationException?

4
异常出现在以下代码中:
private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
   ActiveDownloadJob adJob = e.UserState as ActiveDownloadJob;
   if (adJob != null && adJob.ProgressBar != null)
   {
      adJob.ProgressBar.Invoke((Action)(() => adJob.ProgressBar.Value = e.ProgressPercentage));
   }
}

在线上:

adJob.ProgressBar.Invoke((Action)(() => adJob.ProgressBar.Value = e.ProgressPercentage));

这是form1中的ActiveDownloadJob类:
class ActiveDownloadJob
{
            public DownloadImages.DownloadData DownloadData;
            public ProgressBar ProgressBar;
            public WebClient WebClient;

            public ActiveDownloadJob(DownloadImages.DownloadData downloadData, ProgressBar progressBar, WebClient webClient)
            {
                try
                {
                    this.DownloadData = downloadData;
                    this.ProgressBar = progressBar;
                    this.WebClient = webClient;
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.ToString());
                }
            }
        }

我不确定是否需要调用这行代码,因为现在我没有使用BackgroundWorker,但我不确定。

完整的异常信息是:无法在控件的窗口句柄创建之前调用Invoke或BeginInvoke。

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
  Source=System.Windows.Forms
  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 System.Windows.Forms.Control.Invoke(Delegate method)
       at WeatherMaps.Form1.DownloadProgressCallback(Object sender, DownloadProgressChangedEventArgs e) in d:\C-Sharp\WeatherMaps\WeatherMaps\WeatherMaps\Form1.cs:line 290
       at System.Net.WebClient.OnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
       at System.Net.WebClient.ReportDownloadProgressChanged(Object arg)
  InnerException: 

如何在不使用Invoke的情况下更改此行?如果需要使用Invoke,我该如何修复这行和异常?

我知道我应该在Form1窗体关闭事件中处理它,但是怎么处理?在Form1窗体关闭事件中应该做什么?


你读了异常信息吗? - Lasse V. Karlsen
在窗口句柄被创建之前,无法在控件上调用Invoke或BeginInvoke方法。 看起来你的进度条没有放置在窗体上,或者它不可见,或者类似于这样的情况。你是什么时候调用下载任务的? - Alexander Kuzin
3个回答

5

是的,你会得到一个异常,因为Invoke需要将“Message”发布到“消息循环”,但Handle尚未创建。

使用InvokeRequired查看是否需要Invoke,当Handle尚未创建时,它将返回false,因此可以直接调用它。

var method = (Action)(() => adJob.ProgressBar.Value = e.ProgressPercentage);
if(adJob.ProgressBar.InvokeRequired)
    adJob.ProgressBar.Invoke(method);
else
    method();

3
问题在于您试图在进度条具有窗口句柄之前修改它。解决方法之一是:
if (adJob.ProgressBar.Handle != IntPtr.Zero)
{
    adJob.ProgressBar.Invoke((Action)(() =>
        adJob.ProgressBar.Value = e.ProgressPercentage));
}

这很可能是因为您在 Form 实际显示之前调用了此方法。

Michael,我尝试了一下,将旧代码删除并添加了你的代码进行测试,但是在以下这行代码上出现了异常:if (adJob.ProgressBar.Handle != IntPtr.Zero) ObjectDisposedException: Cannot access a disposed object。当程序正在运行时,进度条正在工作,而我关闭程序时,出现了右上角的X红色按钮。我没有在form1的关闭事件中添加任何内容。 - Doron Muzar
@DoronMuzar,你需要在关闭程序之前停止线程。你可以通过连接到“Closing”事件来实现这一点。 - Mike Perrenoud

-1

试一下:

MethodInvoker mi = () => adJob.ProgressBar.Value = e.ProgressPercentage;
if(InvokeRequired) BeginInvoke(mi);
else mi();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接