C# 跨线程操作在 Windows 窗体中无效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13945225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cross-thread operation not valid in Windows Forms
提问by Terrii
Could anyone help me i have a problem I'm trying to get this code to work in the background via threadpool but i cannot seem to get it to work i keep getting this error:
任何人都可以帮助我我有一个问题我正在尝试通过线程池让这段代码在后台工作,但我似乎无法让它工作,我一直收到这个错误:
Cross-thread operation not valid: Control 'ListBox3' accessed
from a thread other than the thread it was created on.
Here is the code i am using:
这是我正在使用的代码:
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";
}
}
}
}
}
采纳答案by jac
You need to invoke a delegate to update the list. See this MSDN example.
您需要调用委托来更新列表。请参阅此MSDN 示例。
回答by Dan OConnell
You can't access the control from a separate thread, it has to be from the same thread that the control was created from.
您不能从单独的线程访问控件,它必须来自创建控件的同一线程。
回答by Brian Rasmussen
I'm assuming that DoWork
is launched on another thread. The code accesses ListBox3
, which is a GUI control. .NET restricts access to GUI controls to the thread that created them.
我假设它DoWork
是在另一个线程上启动的。代码访问ListBox3
,这是一个 GUI 控件。.NET 将对 GUI 控件的访问限制为创建它们的线程。
回答by jac
You can do this instead as accessing controls from other than UI thread require invoke.
您可以改为执行此操作,因为从 UI 线程以外的其他线程访问控件需要调用。
When you start (I assume you use BackgroundWorker), pass in the url from your textbox to RunWorkerAsync(TxtServer.Text)
as argument, then:
当您开始时(我假设您使用 BackgroundWorker),将文本框中的 urlRunWorkerAsync(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;
}
Then on your Completed event cast e.result to list and add it to your control.
然后在您的 Completed 事件上将 e.result 转换为 list 并将其添加到您的控件中。
回答by Parviz Bazgosha
You can access controll by do this
您可以通过执行此操作来访问控制
Invoke(new Action(() => {Foo.Text="Hi";}));
回答by SkeetJon
This extension method solves the problem too.
这种扩展方法也解决了这个问题。
/// <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);
}
}
Use in your worker thread as follows
在您的工作线程中使用如下
InvokeEx(x => x.MyControl.Text = "foo");
回答by Steve
You can also access controls via invoke using the following syntax with an Action delegate:
您还可以使用以下语法和 Action 委托通过调用访问控件:
Invoke((Action)(() =>
{
var myVar = SomeWinFormControl.Property;
}));