2012-02-13 182 views
0

我遇到了一些麻煩,我的MVP解決方案,可能線程相關。我正在運行Compact Framework 3.5並使用C#。我可以使用OpenNETCF,因此我可以使用BackgroundWorker。MVP與背景工作者(異常提出)

我有一段代碼(MyClient),它使用套接字連接到Web服務器。代碼連接到服務器並下載數據(無休止的,它的一個流),直到用戶停止它。因爲數據的下載是無止境的,所以必須在一個線程中運行,我認爲這是我遇到問題的地方。 MyClient對象具有一個狀態,表示爲enum OnOff,Connecting編輯 - 爲了澄清,當調用MyClient.Start()時,它連接到服務器。然後,它將連接並保存,以便在線程運行中不斷下載數據。所以當Stop()被調用時,它只需要一個布爾標誌來告訴MyClient內部使用的線程停止。爲了清晰起見,下面的縮寫版本。

public void Start() 
{ 
     //... 
     //Code to Connect to server... 
     stream = _connection.GetStream(); 
     //... 
     //Code to send/receive data to confirm connection... 

     State = State.On; 

     //Start thread to read data constantly until stopped by user setting "_continueReadingData = false" 
     _continueReadingData = true; 
     Thread readData = new Thread(ReadData); 
     readData.IsBackground = true; 
     readData.Start(); 
     //Note readData uses the stream variable saved above 

} 

查看電話主持人_presenter.TurnOn();。演示者使用_model.Start();調用模型。這個想法是,MyClient代碼開始運行,報告其狀態變化並在後臺運行,直到用戶單擊停止。 View受UI組件上的Invoke/BeginInvoke調用的保護。

我附上了我的模型的代碼示例如下。最初我使用了一個普通的線程並使其工作,如下所示,它被註釋掉了。這裏有兩個問題,需要使用Invoke將所有到達視圖的UI線程編組回到UI線程,而且這裏的問題是引發的任何異常都不會返回到UI線程,因此不能處理並且會崩潰應用。這是我想要解決的兩個問題。

我已經嘗試了BackgroundWorker(可在OpenNETCF中使用,就像在.Net 2.0以上的普通BackgroundWorker中一樣),以處理下面的代碼中的異常和編組。但有了這個,我無法讓它工作。取而代之的是,狀態改變並回報GUI。儘管Invoke被調用,但它仍然以InvalidOperationException - "Invoke or BeginInvoke cannot be called on a control until the window handle has been created"進行投訴。做一些研究幾乎聽起來像線程正在創建自己的一套控件。在這一點上我很困惑。

任何人都可以借用手來告訴我如何正確地啓動/結束模型中的線程,以便它們在後臺運行,將異常返回到要處理的模型,然後將執行回傳到UI線程,以便您不必在每個控件上使用Invoke。我相信這一定是可能的。

public class Model 
{ 
    public event EventHandler DataChanged; 
    public event EventHandler ErrorRaised; 
    private MyClient _client = new MyClient(); 

    public Model() 
    { 
     //Register to events 
     _client.StateChanged += ClientStateChanged; 

     //Setup current values 
     State = _client.State; 
    } 

    void ClientStateChanged(NTRIPClient client, NTRIPState newState) 
    { 
     State = newState; 
    } 

    private State _state; 
    public State State 
    { 
     get { return _state; } 
     set 
     { 
      if (_state != value) 
      { 
       _state = value; 
       if (DataChanged != null) 
       { 
        DataChanged(this, EventArgs.Empty); 
       } 
      } 
     } 
    } 

    public void Start() 
    { 
     //Thread thread = new Thread(_NTRIPClient.Start); 
     //thread.IsBackground = true; 
     //thread.Start(); 

     BackgroundWorker bgWorker = new BackgroundWorker(); 
     bgWorker.DoWork += _client.Start(); 
     bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted; 
    } 

    void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if(e.Error != null) 
     { 
      if (ErrorRaised != null) 
      { 
       ErrorRaised(this, new ErrorEventArgs(e.Error)); 
      } 
     } 
    } 
} 
+1

有在http://stackoverflow.com/questions/1862590/how-to-update-gui-with-backgroundworker類似的討論。也許這將有助於 – 2012-02-14 18:53:01

+0

謝謝拉夫。在發佈之前,我閱讀了一個。我認爲它接近。但ProgressUpdated/Completed並不能幫助我,因爲MyClient代碼不知道它正在後臺工作中運行,所以不會引發進度更新事件。此外,GUI需要被通知屬性改變,即狀態。然而,當狀態改變時,事件在非UI線程上被引發。我想知道我的客戶是否要重寫,以某種方式支持後臺工作人員 – JonWillis 2012-02-14 19:05:14

回答

0

問題原來是主持人在視圖中創建,而視圖又創建了模型。這個模型在視圖完全構建之前調用,因此控件尚未創建。

一個很大的問題是由於一個簡單的錯誤:)