C# 尽管设置了ApartmentState,但仍存在跨线程错误
我正在尝试向我的UI显示循环的内容。首先,我不确定我是否以正确的方式(使用WinForms)实现了这一点,但这就是我正在做的:C# 尽管设置了ApartmentState,但仍存在跨线程错误,c#,multithreading,C#,Multithreading,我正在尝试向我的UI显示循环的内容。首先,我不确定我是否以正确的方式(使用WinForms)实现了这一点,但这就是我正在做的: foreach (string item in stringArray) { Thread thread = new Thread(delegate() { UpdatedResultEvent(item);
foreach (string item in stringArray)
{
Thread thread = new Thread(delegate()
{
UpdatedResultEvent(item);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
我希望这是足够的信息,但如果不是这样,我将在这里详细介绍
我有两个类,我的Program.cs(WinForm)和另一个名为logicClass的类。我将程序对象的实例传递给logicClass。我的logicClass有一个委托,其签名与程序类中的方法匹配。作为委托传递的方法是
public void UpdateResultsOnScreen(string newContent)
{
txtResults.Text += newContent;
}
错误消息是
跨线程操作无效:从线程访问控件
而不是创建它的线程
编辑
与进度条的工作方式类似,目标是看到控件实时更新。目前,即使它确实工作,线程也不会将“结果”返回到屏幕,直到线程完成 即使您正在设置ApartmentState,也必须在从另一个(非UI)线程访问时调用UI控件 确保在UpdateResultEvent方法中调用UI控件 不管怎样,你所做的不是一个好主意,考虑使用一个或“/P>”。 它会自动扩展您的代码,产生大量线程会降低性能,特别是当您的集合中包含大量项目时。使用此选项(如果您使用WinForms):
public void UpdateResultsOnScreen(字符串newContent)
{
txtResults.BeginInvoke(
新操作((值)=>
{
txtResults.Text+=值;
}),
新内容);
}
也如<强> iNoMAial所说,考虑使用<代码>线程池> />代码>或<代码>并行。p>
public void UpdateResultsOnScreen(string newContent)
{
if(txtResults.InvokeRequired)
{
txtResults.Invoke(
new Action<string>(content => txtResults.Text += content), newContent);
return;
}
txtResults.Text += newContent;
}
public void UpdateResultsOnScreen(字符串newContent)
{
if(txtResults.InvokeRequired)
{
txtResults.Invoke(
新操作(content=>txtreults.Text+=content),newContent;
返回;
}
txtResults.Text+=新内容;
}
这真的很好,但它不会在屏幕上实时显示我的结果。我的文本框仍然一次显示所有内容,而不是一次填充一个项目。例如,假设每次调用UpdatedResultEvent(项)都需要5秒钟(由于数据库/Web服务调用等原因)。这意味着我希望我的屏幕每5秒钟更新一次。@DaveRook请尝试我编辑的代码。我认为,即使是旧代码(Invoke
)也应该像您所期望的那样工作并更新UI,但是如果它不工作,我们需要知道您是如何准确地完成它的。我想这应该是另一个问题。是的,我已经用BeginInvoke()尝试过了,但结果相同。如果你认为这应该是可行的,那么也许我的设计中还有其他地方是错误的@大卫:是的,我认为它应该会起作用。通过使用单独的线程,您不会阻塞UI线程。通过使用Invoke
或BeginInvoke
方法,您将向UI发送一条消息,并告诉它进行自我更新。因此,它应该可以工作,除非您以其他方式阻止UI,比如使用thread.Join()
。不,不使用thread.Join,也不睡眠线程。嗯,一定是我的密码错了。非常感谢。
public void UpdateResultsOnScreen(string newContent)
{
if(txtResults.InvokeRequired)
{
txtResults.Invoke(
new Action<string>(content => txtResults.Text += content), newContent);
return;
}
txtResults.Text += newContent;
}