与后台工作者的MVP(提出异常)

时间:2012-02-13 18:25:11

标签: c# winforms multithreading marshalling mvp

我的MVP解决方案遇到了一些问题,可能与线程有关。我正在运行Compact Framework 3.5并使用C#。我可以使用OpenNETCF,因此我可以使用BackgroundWorker。

我有一段代码(MyClient)使用套接字连接到Web服务器。代码连接到服务器并下载数据(无休止地,它是一个流),直到用户停止它。因为数据的下载是无止境的,所以必须在一个线程中运行,我认为这是我遇到问题的地方。 MyClient对象具有状态,表示为枚举OnOffConnecting编辑 - 只是为了澄清,当调用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));
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

问题原来是在视图中创建了演示者,而视图又创建了模型。在完全构建视图之前调用此模型,因此尚未创建控件。

由于一个简单的错误引起的一个大问题:)