我的MVP解决方案遇到了一些问题,可能与线程有关。我正在运行Compact Framework 3.5并使用C#。我可以使用OpenNETCF,因此我可以使用BackgroundWorker。
我有一段代码(MyClient
)使用套接字连接到Web服务器。代码连接到服务器并下载数据(无休止地,它是一个流),直到用户停止它。因为数据的下载是无止境的,所以必须在一个线程中运行,我认为这是我遇到问题的地方。
MyClient
对象具有状态,表示为枚举On
,Off
,Connecting
。
编辑 - 只是为了澄清,当调用MyClient.Start()时,它会连接到服务器。然后它接受该连接并保存它以便在Thread运行中使用以不断下载数据。因此,当调用Stop()时,只需要获取一个bool标志来告诉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线程,因此无法处理并且会崩溃应用。这是我要解决的两个问题。
我已经尝试过BackgroundWorker(在OpenNETCF中可用,就像.Net 2.0以后的普通BackgroundWorker一样)来处理异常和编组,如下面的代码所示。但有了这个,我无法让它发挥作用。而是在更改State并将其报告回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));
}
}
}
}
答案 0 :(得分:0)
问题原来是在视图中创建了演示者,而视图又创建了模型。在完全构建视图之前调用此模型,因此尚未创建控件。
由于一个简单的错误引起的一个大问题:)