我是一名不熟练的C#编码器,这就是为什么无论互联网上的信息量多少,这个问题都让我感到非常困难。
我实际上是在一个计时器上创建一个程序,它反复轮询网站以获取一些信息。在此过程中,将创建WebBrowser控件以导航到信息(身份验证所需)。该程序在启动时运行这一系列事件,然后使用System.Timers.Timer设置为每10分钟(当然,调试次数较少)来执行相同系列的事件,但当我的Timer.Elapsed事件触发该过程时,我得到一个:
ThreadStateException ,其描述为 ActiveX控件'8856f961-340a-11d0-a96b-00c04fd705a2'无法实例化,因为当前线程不在单线程单元中。
这是我程序的精简版。
private void Form1_Load(object sender, EventArgs e)
{
GetDataFromWebBrowser();
Set_Auto_Refresh_Timer();
}
private void Set_Auto_Refresh_Timer()
{
System.Timers.Timer TimerRefresh = new System.Timers.Timer(10000);
TimerRefresh.Elapsed += new System.Timers.ElapsedEventHandler(TimerRefresh_Elapsed);
TimerRefresh.AutoReset = true;
TimerRefresh.Start();
}
private void TimerRefresh_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GetDataFromWebBrowser();
}
private void GetDataFromWebBrowser()
{
WebBrowser wb = new WebBrowser(); <--This is where the error is thrown.
...get web data...
}
我认为我在那里有足够的代码来描绘图片。正如您所看到的,当它创建另一个WebBrowser时,它会抛出错误。
我真的很难过,我只是开始在线程上刮起表面,这可能就是我为什么这么难过的原因。
//我的解决方案/ 我最终将WebBrowser创建移出方法,并使其静态以重用WebBrowser控件。我还将System.Timers.Timer交换为System.Threading.Timer。似乎解决了这个问题。
答案 0 :(得分:7)
MSDN documentation for WebBrowser表示:
WebBrowser类只能在设置为单线程单元(STA)模式的线程中使用。要使用此类,请确保您的Main方法标有[STAThread]属性。
另外,如果您希望定期与UI控件进行交互,请将System.Timers.Timer
更改为System.Windows.Forms.Timer
。或者,将System.Timers.Timer
的{{3}}属性设置为父控件,以强制计时器调用右侧线程上的调用。所有WinForms控件只能从同一个,唯一的UI线程访问。
.NET的BCL中有三种类型的计时器,每种计时器的表现都截然不同。请查看此MSDN文章以进行比较:SynchronizingObject或此Comparing the Timer Classes in the .NET Framework Class Library (web archive)。
答案 1 :(得分:3)
我建议使用WebClient类而不是WebBrowser。此外,将已创建的实例存储为私有属性似乎更好,而不是每次需要轮询网站时创建新实例。
如下:
private WebClient webClient;
private void Form1_Load(object sender, EventArgs e)
{
GetDataFromWebBrowser();
Set_Auto_Refresh_Timer();
this.webClient = new WebClient();
}
private void Set_Auto_Refresh_Timer()
{
System.Timers.Timer.TimerRefresh = new System.Timers.Timer(10000);
TimerRefresh.Elapsed += new System.Timers.ElapsedEventHandler(TimerRefresh_Elapsed);
TimerRefresh.AutoReset = true;
TimerRefresh.Start();
}
private void Set_Auto_Refresh_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GetDataFromWebBrowser();
}
private void GetDataFromWebBrowser()
{
...perform required work with webClient...
...get web data...
}
答案 2 :(得分:0)
正如Groo所说,你应该使用 System.Windows.Forms.Timer ,或者如果你真的想在另一个线程中进行操作,你应该使用Invoke方法做任何UI相关的东西:
private void GetWebData()
{
...get web data...
}
private void ShowWebData()
{
WebBrowser wb = new WebBrowser();
// other UI stuff
}
private void TimerRefresh_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GetDataFromWebBrowser();
}
private void GetDataFromWebBrowser()
{
GetWebData();
if (this.InvokeRequired)
this.Invoke(new Action(ShowWebData));
else
ShowWebData();
}