我是编程和WPF架构的新手。我有一个使用backgroundworker类的WPF应用程序。但是,它始终抛出错误“调用线程必须是sta,因为许多ui组件需要这个”。我需要添加STAThread属性我的main方法。但我不知道该怎么做。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
InitializeBackgroundWorker();
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
tabItemList.CollectionChanged += this.TabCollectionChanged;
}
}
private void InitializeBackgroundWorker()
{
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}
// This event handler is where the actual,
// potentially time-consuming work is done.
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
//e.Result = AddTabitem((int)e.Argument, worker, e);
AddTabitem((string)e.Argument, worker, e);
}
void AddTabitem(string filePath, BackgroundWorker worker, DoWorkEventArgs e)
{
if (File.Exists(filePath))
{
//This line which throws error "the calling thread must be sta because many ui components require this"
RichTextBox mcRTB = new RichTextBox();
rtbList.Add(mcRTB);
}
答案 0 :(得分:2)
您必须在线程启动之前设置ApartmentState 。
http://blogs.msdn.com/b/jfoscoding/archive/2005/04/07/406341.aspx
要在WPF应用中设置公寓状态,
将[STAThread]
属性添加到您的应用中,例如this:
public partial class App : Application
{
App()
{
InitializeComponent();
}
[STAThread]
static void Main()
{
Window1 window = new Window1();
App app = new App();
app.Run(window);
}
}
答案 1 :(得分:1)
编辑:
我对STAThread的了解,因为这不是你的问题。
在查看更新的后台工作程序代码之后,您尝试从后台工作程序线程更新UI。正如您所经历的那样,这不会起作用。你有几个选择:
1)而不是直接更新RichTextBox,而是更新已经数据绑定到您正在更新的属性的变量。有关数据绑定的概述,请参阅此文章,因为您已声明自己是WPF的新手: http://msdn.microsoft.com/en-us/library/ms752347(v=vs.110).aspx
2)使用Invoke而不是直接设置属性。无论如何,您可能需要为选项1执行此操作。这可能是您最直接的快速解决方案。以下是WPF调度程序的一个很好的理由,这是调用业务所需要的:http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher
它会像这样工作: mcRTB.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Normal, 新动作( 代表() { mcRTB.Text ="你好&#34 ;; } ));
以上是更改财产。你可以调整它来调用你的rtbList的.Add方法。
3)想避免调用?使用后台工作人员的报告进度!当你在BW中告诉它时会触发此事件,然后你可以在主UI线程上做一些工作,而不必担心调用东西。
初始化你的BW时,请在那里添加:
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.ProgressChanged += new ProgressChanged EventHandler(backgroundWorker1_ProgressChanged);
然后在您的回调中(或者使用+ =为您自动处理),您可以在UI线程上进行操作。您可以通过执行此操作告诉您的BW报告一些进展:
// the int in the first parameter is arbitrary
// the object can be any object. This is how you pass actual data to your call back
backgroundWorker1.ReportProgress(1,new object())
以下是关于报告进度的精彩读物: http://msdn.microsoft.com/en-us/library/a3zbdb1t(v=vs.110).aspx