2012-12-19 28 views
4

任何人都可以帮助我我有一个问题我试图让这段代码在后台通过线程池工作,但我似乎无法得到它的工作我不断收到此错误:在Windows窗体中无效的跨线程操作

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"; 
       } 
      } 
     } 
    } 
} 

回答

5

您需要调用委托来更新列表。请参阅MSDN example

+0

这是正确答案 - 如果需要,可以使用委托调用。查看提供的链接中的“线程安全调用Windows窗体控件”部分。 – Algirdas

2

你不能从一个单独的线程访问控制,它必须从控制从创建的同一个线程。

1

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

+0

所以会如何解决这个问题? – Terrii

+0

您需要将对控件的访问封送回UI线程。你是怎么调用DoWork的? –

+0

当按钮被点击时,它执行以下命令:ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork)); – Terrii

1

您可以这样做,而不是从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; 
} 

然后在你完成的情况下投e.result列出并添加它到你的控制。

7

通过这样做

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

这个扩展方法也解决了这个问题,您可以访问控制研究。

/// <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"); 
1

您也可以使用下面的语法与Action委托访问通过调用控件:

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