【问题标题】:Cross-thread operation not valid in Windows Forms跨线程操作在 Windows 窗体中无效
【发布时间】:2012-12-06 09:10:55
【问题描述】:

谁能帮助我我有一个问题我试图通过线程池让这段代码在后台工作,但我似乎无法让它工作我一直收到这个错误:

Cross-thread operation not valid: Control 'ListBox3' accessed
from a thread other than the thread it was created on. 

这是我正在使用的代码:

private void DoWork(object o)
{
    var list = ListBox3;

    var request = createRequest(TxtServer.Text, WebRequestMethods.Ftp.ListDirectory);

    using (var response = (FtpWebResponse)request.GetResponse())
    {
        using (var stream = response.GetResponseStream())
        {
            using (var reader = new StreamReader(stream, true))
            {
                while (!reader.EndOfStream)
                {
                    list.Items.Add(reader.ReadLine());
                    ResultLabel.Text = "Connected";
                }
            }
        }
    }
}

【问题讨论】:

    标签: c# winforms ftp threadpool invoke


    【解决方案1】:

    您可以通过这样做访问控制

     Invoke(new Action(() => {Foo.Text="Hi";}));
    

    【讨论】:

      【解决方案2】:

      您需要调用委托来更新列表。看到这个MSDN example

      【讨论】:

      • 这是正确的答案 - 如果需要,使用委托调用。查看提供的链接中的“对 Windows 窗体控件的线程安全调用”部分。
      【解决方案3】:

      这个扩展方法也解决了这个问题。

      /// <summary>
      /// Allows thread safe updates of UI components
      /// </summary>
      public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
      {
          if (@this.InvokeRequired)
          {
              @this.Invoke(action, new object[] { @this });
          }
          else
          {
              action(@this);
          }
      }
      

      在你的工作线程中使用如下

      InvokeEx(x => x.MyControl.Text = "foo");
      

      【讨论】:

        【解决方案4】:

        您还可以使用以下语法和 Action 委托通过调用来访问控件:

         Invoke((Action)(() =>
         {
              var myVar = SomeWinFormControl.Property;
         }));
        

        【讨论】:

          【解决方案5】:

          您不能从单独的线程访问控件,它必须来自创建控件的同一线程。

          【讨论】:

            【解决方案6】:

            我假设DoWork 在另一个线程上启动。代码访问ListBox3,这是一个GUI 控件。 .NET 将对 GUI 控件的访问限制为创建它们的线程。

            【讨论】:

            • 您需要将对控件的访问封送回 UI 线程。你是如何调用DoWork的?
            • 当按钮被点击时它会执行这个命令:ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
            【解决方案7】:

            您可以这样做,因为从 UI 线程以外的地方访问控件需要调用。

            当您开始时(我假设您使用 BackgroundWorker),将文本框中的 url 作为参数传递给 RunWorkerAsync(TxtServer.Text),然后:

            private void DoWork(object o, DoWorkEventArgs e)
            {
                string Url = (string) e.Argument;
            
                List<of string> tmpList = new List<of string>;
            
                var request = createRequest(url, WebRequestMethods.Ftp.ListDirectory);
            
                using (var response = (FtpWebResponse)request.GetResponse())
                {
                    using (var stream = response.GetResponseStream())
                    {
                        using (var reader = new StreamReader(stream, true))
                        {
                            while (!reader.EndOfStream)
                            {
                                list.Add(reader.ReadLine());
                                //ResultLabel.Text = "Connected";
                                //use reportprogress() instead
                            }
                        }
                    }
                }
                e.result = tmpList;
            }
            

            然后在您的 Completed 事件中将 e.result 转换为列表并将其添加到您的控件中。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-08-16
              • 2011-07-11
              • 1970-01-01
              • 2015-12-13
              • 1970-01-01
              相关资源
              最近更新 更多