【发布时间】:2012-02-13 18:25:11
【问题描述】:
我的 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)来处理异常和编组,如下面的代码所示。但是有了这个,我无法让它工作。相反,当状态更改并报告回 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));
}
}
}
}
【问题讨论】:
-
stackoverflow.com/questions/1862590/… 也有类似的讨论。也许这会有所帮助
-
谢谢拉尔夫。我在发帖前读过那个。我认为它很接近。但是 ProgressUpdated/Completed 对我没有帮助,因为 MyClient 代码不知道它正在后台工作人员中运行,因此不会引发进度更新事件。还需要通知 GUI 属性更改,即状态。然而,当状态改变时,该事件会在非 UI 线程上引发。我想知道是否要重写我的客户以某种方式支持后台工作人员
标签: c# winforms multithreading marshalling mvp