2011-12-04 18 views
0

我正在編寫一個用於監視的GUI應用程序,我希望得到關於它的邏輯的一些建議。基本上所有應用程序需要做的就是每隔x分鐘連接一臺遠程服務器,檢查是否有更改,如果有更改,對它們進行操作(更新本地數據庫等等,具體取決於更改)。用於監視更改的應用程序

我的第一個想法是:

  1. 有一個複選框(監控ON/OFF)。點擊(如果選中)啓動計時器。
  2. 定時器在其Tick方法中啓動BackgroundWorker。
  3. 的DoWork方法執行連接/檢索信息的東西
  4. 一)上WorkDone處理方法從後臺工作的信息和對WorkDone處理方法確實有其 b本地更新)觸發的自定義事件「的一個或多個SomethingChanged 「取決於它得到的變化; EventListeners從那裏處理本地更新。

我的主要問題是從Timer中調用Worker,因爲我將工作人員添加到窗體,現在他們在不同的線程(是正確的描述?),然後傳遞結果是類似的問題。我正在閱讀有關代表,但仍然不確定在何時以及如何使用什麼,以及首先確實需要使用什麼。我是否需要bgWorker和Timer?我是否需要自定義事件,或者是否可以使用Switch(result)在workDone中完成所有工作?這個總體原則首先是好的,也許有更好的東西,我正在重新發明輪子?先謝謝你! ),這將是安全地調用bgWorker.RunWorkerAsync( -

回答

2

從體系結構的角度來看:

消息隊列將應用程序的位分開。您可以在Windows窗體應用程序中依賴Windows爲您創建和管理的Message Queue。 Google for PostMessage/GetMessage等。這通常稱爲「消息傳遞」。

典型Arcitecture您的應用程序的

  • 一部分「推」的請求進入隊列
  • 您的應用程序的其它部分從隊列中「拉」的請求和結果寫入第二個隊列。
  • 第一部分可以從第二個「結果」隊列「拉」請求並顯示給用戶。

所以它看起來像這樣:

應用程序 - >請求的隊列 - >處理引擎 - >結果隊列 - >應用

處理引擎可以在同一應用程序,在同一個線程或不同的線程/進程(甚至不同的機器)上。

您可以使用簡單的隊列:說一個Queue<string>()(只要您使用鎖來訪問它)或增加複雜性或更多更復雜/功能的隊列。

問題與天真策略和其他解決方案...事情要考慮:

  1. ,如果你做一個新的請求,而舊的還未完成,會發生什麼?
  2. 如果發生錯誤會怎麼樣?你想內聯錯誤嗎?你可以使用另一個隊列的錯誤?
  3. 你想重試嗎?
  4. 如果信息丟失會發生什麼? (即請求被推送,但沒有響應進入...)?有事務性隊列等

示例代碼

object oLock = new object(); 
    Queue<string> requests = new Queue<string>(); 
    Queue<string> responses = new Queue<string>(); 
    Thread mThread; 
    AutoResetEvent mEvent = new AutoResetEvent(false); 

    public Form1() 
    { 
     InitializeComponent(); 
     mThread = new Thread(ProcessingEngine); 
     mThread.IsBackground = true; 
     mThread.Start(); 
    } 

    private void ProcessingEngine() 
    { 
     string result; 
     string request = null; 

     while (true) 
     { 
      try 
      { 
       mEvent.WaitOne(); 

       lock (oLock) 
       { 
        request = requests.Dequeue(); 
       } 

       var wc = new WebClient(); 
       result = wc.DownloadString(request); 

       lock (oLock) 
       { 
        responses.Enqueue(result); 
       } 
      } 
      catch (Exception ex) 
      { 
       lock (oLock) 
       { 
        responses.Enqueue(ex.ToString()); 
       } 
      } 
     } 
    } 


    private void timer1_Tick(object sender, EventArgs e) 
    { 
     lock (oLock) 
     { 
      //Stick in a new request 
      requests.Enqueue("http://yahoo.com"); 

      //Allow thread to start work 
      mEvent.Set(); 

      //Check if a response has arrived 
      if (responses.Any()) 
      { 
       var result = responses.Dequeue(); 
       listBox1.Items.Add(result.Substring(1,200)); 
      } 
     } 
    } 
} 
0

如果使用System.Windows.Forms.Timer而不是System.Threading.Timer,你Tick處理器將從窗體的消息循環中調用,你就會有完全訪問所有控件。至於檢索結果 - RunWorkerCompleted也從消息循環線程調用,您可以在這裏安全地更新您的用戶界面。

+1

-1。這破壞了可伸縮性,如果線程例子超時 - UI會阻塞,直到超時發生,這是不好的。使用Threading.Timer允許在單獨的線程上執行,然後調用回主線程(窗口上的Invoke方法),僅用於UI更新。 – TomTom

+0

怎麼回事?我還沒有看到RunWorkerAsync在任何時候都會阻塞的情況,你不能直接從Threading.Timer.Tick中更新UI,並且在Timer中使用'Invoke'''會得到與'RunWorkerCompleted'更新結果完全相同的結果。 DoWork'在它自己的線程中執行,所以請解釋你爲什麼認爲UI會阻塞。 – MagnatLU

+0

Comp投票,這樣做沒有錯。不會發生阻塞,試圖運行繁忙的BGW會產生異常。用任何一種計時器。至少它放鬆了OP對擁有太多線程的擔憂。 –

0

解決方案很簡單 - 調用回主線程。這是winform控件上的調用方法。這將基本上改變線程執行到UI線程,並允許您操作UI。

做這個「阻止」(即不是每個控件一次,但有一次,當你有新聞)。