簡體   English   中英

定時器和線程有問題

[英]Trouble with timers and threads

我是一個不熟練的C#編碼器,這就是為什么無論互聯網上的信息量如何,這個問題都讓我感到非常困難。

我實際上是在一個計時器上創建一個程序,它反復輪詢網站以獲取一些信息。 在此過程中,將創建WebBrowser控件以導航到信息(身份驗證所需)。 該程序在啟動時運行這一系列事件,然后使用System.Timers.Timer設置為每10分鍾(當然,調試次數較少)來執行相同系列的事件,但當我的Timer.Elapsed事件觸發該過程時,我得到A:

無法實例化描述為ActiveX控件'8856f961-340a-11d0-a96b-00c04fd705a2'的 ThreadStateException因為當前線程不在單線程單元中。

這是我的程序的精簡版。

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。 似乎解決了這個問題。

WebBrowserMSDN文檔指出:

WebBrowser類只能在設置為單線程單元(STA)模式的線程中使用。 要使用此類,請確保使用[STAThread]屬性標記 Main方法。

此外,如果要以固定間隔與UI控件進行交互,請將System.Timers.Timer更改為System.Windows.Forms.Timer 或者,將System.Timers.TimerSynchronizingObject屬性設置為父控件,以強制計時器調用右側線程上的調用。 所有WinForms控件只能從同一個,唯一的UI線程訪問。

.NET的BCL中有三種類型的定時器,每種定時器的行為都截然不同。 查看此MSDN文章以進行比較: 比較.NET Framework類庫(Web存檔)中的Timer類或此簡要比較表

我建議使用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...

        }

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM