我遇到了一些麻煩,我的MVP解決方案,可能線程相關。我正在運行Compact Framework 3.5並使用C#。我可以使用OpenNETCF,因此我可以使用BackgroundWorker。MVP與背景工作者(異常提出)
我有一段代碼(MyClient
),它使用套接字連接到Web服務器。代碼連接到服務器並下載數據(無休止的,它的一個流),直到用戶停止它。因爲數據的下載是無止境的,所以必須在一個線程中運行,我認爲這是我遇到問題的地方。 MyClient
對象具有一個狀態,表示爲enum On
,Off
,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));
}
}
}
}
有在http://stackoverflow.com/questions/1862590/how-to-update-gui-with-backgroundworker類似的討論。也許這將有助於 – 2012-02-14 18:53:01
謝謝拉夫。在發佈之前,我閱讀了一個。我認爲它接近。但ProgressUpdated/Completed並不能幫助我,因爲MyClient代碼不知道它正在後臺工作中運行,所以不會引發進度更新事件。此外,GUI需要被通知屬性改變,即狀態。然而,當狀態改變時,事件在非UI線程上被引發。我想知道我的客戶是否要重寫,以某種方式支持後臺工作人員 – JonWillis 2012-02-14 19:05:14