首页 文章

定时器和线程有问题

提问于
浏览
4

我是一个不熟练的C#编码器,这就是为什么无论互联网上的信息量如何,这个问题都让我感到非常困难 .

我实际上是在一个计时器上创建一个程序,它反复轮询网站以获取一些信息 . 在此过程中,将创建WebBrowser控件以导航到信息(身份验证所需) . 该程序在启动时运行这一系列事件,然后使用System.Timers.Timer设置为每10分钟(当然,调试次数较少)来执行相同系列的事件,但当我的Timer.Elapsed事件触发该过程时,我得到A:

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 . 似乎解决了这个问题 .

3 回答

  • 0

    MSDN documentation for WebBrowser指出:

    WebBrowser类只能在设置为单线程单元(STA)模式的线程中使用 . 要使用此类,请确保使用[STAThread]属性标记Main方法 .

    另外,如果要定期与UI控件进行交互,请将 System.Timers.Timer 更改为 System.Windows.Forms.Timer . 或者,将 System.Timers.TimerSynchronizingObject属性设置为父控件,以强制计时器调用右侧线程上的调用 . 所有WinForms控件只能从同一个,唯一的UI线程访问 .

    .NET的BCL中有三种类型的定时器,每种定时器的行为都截然不同 . 请查看此MSDN文章以进行比较:Comparing the Timer Classes in the .NET Framework Class Library (web archive)或此brief comparison table .

  • 7

    我建议使用WebClient class而不是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...
    
            }
    
  • 3

    正如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();
    }
    

相关问题