2012-02-13 54 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

问题原来是主持人在视图中创建,而视图又创建了模型。这个模型在视图完全构建之前调用,因此控件尚未创建。

一个很大的问题是由于一个简单的错误:)